/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2003 Copyright (C)
 *
 *  File: com_api.c
 *
 *  Description:    Common APIs: 
 *                  1.Routines LNB and Scart GPIO control
 *                  2.audio & video control
 *
 *  History:
 *      Date        Author      Version  Comment
 *      ====        ======      =======  =======
 *  1.  2006.02.17  Xianyu Nie   0.1.000  Initial
 *  
 ****************************************************************************/
#include <sys_config.h>
#include <types.h>
#include <basic_types.h>
#include <mediatypes.h>
#include <osal/osal.h>

#include <bus/rtc/rtc.h>
#include <hal/hal_gpio.h>
#include <hld/hld_dev.h>
#include <hld/osd/Osddrv.h>
#include <hld/snd/snd_dev.h>
#include <hld/snd/snd.h>
#include <hld/deca/deca.h>
#include <hld/decv/vdec_driver.h>
#include <hld/dis/vpo.h>
#include <hld/osd/osddrv.h>
#include <hld/sto/sto_dev.h>
#include <hld/scart/scart.h>
#if (TTX_ON == 1) 
#include <hld/vbi/vbi.h>
#include <api/libttx/ttx_osd.h>
#include <api/libttx/lib_ttx.h>
#endif
#if (SUBTITLE_ON == 1) 
#include <hld/sdec/sdec.h>
#include <api/libsubt/lib_subt.h>
#endif

#if (ISDBT_CC==1)
#include <hld/sdec/sdec.h>
#include <api/libisdbtcc/lib_isdbtcc.h>
#endif

#include <math.h>

#include "dev_handle.h"
#include "system_data.h"
#include "com_api.h"
#include <api/libdiseqc/lib_diseqc.h>
#include <api/libosd/osd_common.h>
#include <api/libchunk/chunk.h>
#include <api/libdb/db_interface.h>
#ifndef NEW_DEMO_FRAME
#include <api/libpub29/lib_hde.h>
#else
#include <api/libpub/lib_frontend.h>
#include <api/libpub/lib_hde.h>
#endif
//modify for TTX and EPG share buffer 2011 10 10
#ifdef TTX_EPG_SHARE_MEM
#include <api/libsi/si_eit.h>
#endif
//modify end
#include <hld/dmx/dmx.h>
#ifdef AUDIO_DESCRIPTION_SUPPORT
#include <api/libsi/psi_pmt.h>
#endif
#if (defined(_MHEG5_V20_ENABLE_) && !defined(_BUILD_OTA_E_))
#include <mh5_api/mh5_osd.h>
#endif
#include "../platform/board.h"

#ifdef SD_UI
#define UI_SCREEN_WIDTH 720//1280
#else
#define UI_SCREEN_WIDTH 1280
#endif

#define UI_SCREEN_WIDTH2    720    //720////1280
#define UI_SCREEN_HEIGHT2   576    //576////720

#if 0
#define VMX_API_PRINTF		libc_printf
#else
#define VMX_API_PRINTF(...)	do{}while(0)
#endif

extern sys_state_t      system_state;


void osal_delay_ms(UINT32 ms)
{
    UINT32 i;
    for (i = 0; i < ms; i++)
        osal_delay(1000);
}

/*------------------------------------------------------------

    GPIO related functions : LNB and Scart control
------------------------------------------------------------*/

/*
    sw ---- 0   off
            1   on
*/
void api_Scart_Power_OnOff(unsigned int sw)          // 0: off 1: on  
{
    BoardCfg* cfg = get_board_cfg();
    if(NULL == cfg)
        return;
    if(NULL != cfg->scart_power)
    {
        chip_gpio_set(cfg->scart_power, sw);
    }
    else if(NULL != g_scart_dev && sw == 0)
    {
        scart_io_control(g_scart_dev,SCART_ENTRY_STADNBY,0);        
    }
}


void api_Scart_TVSAT_Switch(unsigned int sw)         // 0: TV  1: SAT
{
    BoardCfg* cfg = get_board_cfg();
    if(NULL == cfg)
        return;
    
    if(NULL != cfg->scart_tvsat_switch)
    {
        chip_gpio_set(cfg->scart_tvsat_switch, sw);
    }
    else if(g_scart_dev)
    {
        UINT32 tvsta_param;
        SYSTEM_DATA *pSys = sys_data_get();

        if(sw == 1)
            tvsta_param = (pSys->avset.tv_ratio == TV_ASPECT_RATIO_43)? ASPECT_4_3 : ASPECT_16_9;
        else
            tvsta_param = ASPECT_INTERNAL;//TV
        scart_io_control(g_scart_dev,SCART_TV_ASPECT,tvsta_param);        
    }
}


/*
    sw ---- 0   4 : 3:
            1   16 : 9
*/
void api_Scart_Aspect_Switch(UINT8 sw)
{
    BoardCfg* cfg = get_board_cfg();
    if(NULL == cfg)
        return;

    if(NULL != cfg->scart_aspect)
    {
        chip_gpio_set(cfg->scart_aspect, sw);
    }    
	else if (g_scart_dev)
	{
		UINT scart_param;
		if(sw == 0)
			scart_param = ASPECT_4_3;
		else
			scart_param = ASPECT_16_9;
		scart_io_control(g_scart_dev,SCART_TV_ASPECT,scart_param);
	}
}

/*
    sw ---- 0   VCR master ( VCR can pass through)
            1   Recevie master  (VCR can't pass through)
*/
void api_Scart_OutPut_Switch(unsigned int sw)
{
    BoardCfg* cfg = get_board_cfg();
    if(NULL == cfg)
        return;
    if(NULL != cfg->scart_vcr_switch)
    {
        chip_gpio_set(cfg->scart_vcr_switch, sw);
    }
	else if (g_scart_dev)
	{
		if(sw == 0)
		{
			scart_io_control(g_scart_dev,SCART_TV_SOURCE,SOURCE_VCR_IN);
		    scart_io_control(g_scart_dev,SCART_VCR_SOURCE,SOURCE_VCR_IN);
		}
		else
		{
			scart_io_control(g_scart_dev,SCART_TV_SOURCE,SOURCE_STB_IN);
		    scart_io_control(g_scart_dev,SCART_VCR_SOURCE,SOURCE_STB_IN);
		}		
	}
	snd_io_control(g_snd_dev, SND_BYPASS_VCR, !sw);
}


void api_Scart_RGB_OnOff(unsigned int sw)
{
	struct vp_io_reg_dac_para dac_reg_para;
    BoardCfg* cfg = get_board_cfg();
    if(NULL == cfg)
        return;
    if(NULL != cfg->scart_tv_fb)
    {
        chip_gpio_set(cfg->scart_tv_fb, sw);
    }
	else if (g_scart_dev)
	{
		UINT32 tv_mode;
		if(sw == 1)
			tv_mode = TV_MODE_RGB;
		else
			tv_mode = TV_MODE_CVBS;
        if(!api_Scart_VCR_Detect())
        {
	        scart_io_control(g_scart_dev,SCART_TV_MODE,tv_mode);
	    }
	}

#if 0//ndef GPIO_RGB_YUV_SWITCH
#ifdef VDAC_USE_RGB_TYPE
if(sw == 0)
	{
		vpo_ioctl(g_vpo_dev,VPO_IO_UNREG_DAC,VDAC_USE_RGB_TYPE);
	}
	else
	{
#ifdef VDAC_USE_SVIDEO_TYPE
		vpo_ioctl(g_vpo_dev,VPO_IO_UNREG_DAC,VDAC_USE_SVIDEO_TYPE);
#endif
		dac_reg_para.eDacType = VDAC_USE_RGB_TYPE;
		dac_reg_para.DacInfo.bEnable = 1;
		dac_reg_para.DacInfo.tDacIndex.uDacFirst    = RGB_DAC_R;
		dac_reg_para.DacInfo.tDacIndex.uDacSecond   = RGB_DAC_G;
		dac_reg_para.DacInfo.tDacIndex.uDacThird    = RGB_DAC_B;
		dac_reg_para.DacInfo.eVGAMode = VGA_NOT_USE;
		dac_reg_para.DacInfo.bProgressive = FALSE;
		vpo_ioctl(g_vpo_dev,VPO_IO_REG_DAC,(UINT32)&dac_reg_para);
	}
#endif
#endif
}

#ifdef VDAC_USE_SVIDEO_TYPE
void api_Svideo_OnOff(unsigned int sw)//sw:1 open,0 close
{
	struct vp_io_reg_dac_para dac_reg_para;
	if(sw == 1)//open SVIDEO
	{
#ifdef VDAC_USE_RGB_TYPE
		vpo_ioctl(g_vpo_dev,VPO_IO_UNREG_DAC,VDAC_USE_RGB_TYPE);//close RGB DAC
#endif
		dac_reg_para.eDacType = VDAC_USE_SVIDEO_TYPE;
		dac_reg_para.DacInfo.bEnable = 1;
		dac_reg_para.DacInfo.tDacIndex.uDacFirst    = SVIDEO_DAC_Y;
		dac_reg_para.DacInfo.tDacIndex.uDacSecond   = SVIDEO_DAC_C;
		dac_reg_para.DacInfo.eVGAMode = VGA_NOT_USE;
		dac_reg_para.DacInfo.bProgressive = FALSE;
		vpo_ioctl(g_vpo_dev,VPO_IO_REG_DAC,(UINT32)&dac_reg_para);
	}
	else
	{
		vpo_ioctl(g_vpo_dev,VPO_IO_UNREG_DAC,VDAC_USE_SVIDEO_TYPE);//close SVIDEO DAC
	}
}
#endif

unsigned int api_Scart_VCR_Detect(void)
{
    BoardCfg* cfg = get_board_cfg();
    if(NULL == cfg)
        return 0;
    if(NULL != cfg->scart_vcr_detech)
    {
        return chip_gpio_get(cfg->scart_vcr_detech);
    }
	else if (g_scart_dev)
	{
		UINT32 vcr_detect = 0;
		
		scart_io_control(g_scart_dev,SCART_CHK_STATE,&vcr_detect);
		if(vcr_detect & SCART_STATE_VCR_IN)
			return 1;
		else
			return 0;
	}
	return 0;
}

UINT8 scart_16_9_ratio = 0xFF;
void api_scart_aspect_callback(UINT8 b_widescr)
{
	scart_16_9_ratio = b_widescr;
}

void api_scart_vcr_callback(UINT32 param)
{
	static UINT32 vcr_detect = 0;

	vcr_detect = 1- vcr_detect;
	osal_interrupt_register_hsr(api_scart_vcr_switch,vcr_detect);
	
	HAL_GPIO_INT_CLEAR(58);
}

void api_scart_vcr_switch(UINT32 param)
{
	SYSTEM_DATA *sys_data = sys_data_get();
	
	if(param)
	{
		api_Scart_RGB_OnOff(0);
		api_Scart_OutPut_Switch(0);
	}
	else
	{
		api_Scart_RGB_OnOff((sys_data->avset.scart_out == SCART_RGB) ? 1 : 0);
#ifdef VDAC_USE_SVIDEO_TYPE
		api_Svideo_OnOff((sys_data->avset.scart_out == SCART_SVIDEO) ? 1 : 0);
#endif
		api_Scart_OutPut_Switch(1);
	}
}
/*------------------------------------------------------------

    Audio & video control function
------------------------------------------------------------*/

void api_audio_set_volume(UINT8 volume)
{
    snd_set_volume(g_snd_dev, SND_SUB_OUT, volume);
}

void api_audio_set_mute(UINT8 flag)
{
    snd_set_mute(g_snd_dev,SND_SUB_OUT,flag);
}

#ifdef AUDIO_DESCRIPTION_SUPPORT
void api_audio_set_ad_volume_offset(INT32 offset)
{
	snd_io_control(g_snd_dev, SND_SET_DESC_VOLUME_OFFSET, offset);
}
#endif

#ifdef DVBT_BEE_TONE
void api_audio_gen_tonevoice(UINT8 level, UINT8 init)
{
	deca_tone_voice(g_deca_dev, level, init);
}

void api_audio_stop_tonevoice(void)
{
	deca_stop_tone_voice(g_deca_dev);
}
#endif

#ifdef AUDIO_SPECIAL_EFFECT
void  api_audio_beep_start(UINT8* data, UINT32 data_len)
{
	struct ase_str_play_param param;
	UINT32 interval; //interval value, from 0 to 100;

	MEMSET(&param, 0, sizeof(struct ase_str_play_param));
	param.loop_cnt = 0xffffffff;
	param.src = data;/*your audio bit stream source start address, must start from the first frame.*/
	param.len = data_len;/*your audio bit stream length in byte*/

	deca_io_control(g_deca_dev, DECA_STR_PLAY, (UINT32)(&param));//start beep
	deca_io_control(g_deca_dev, DECA_BEEP_INTERVAL, 0);
}

void api_audio_beep_set_interval(UINT32 interval)
{
	deca_io_control(g_deca_dev, DECA_BEEP_INTERVAL, interval);
}

void  api_audio_beep_stop(void)
{
	deca_io_control(g_deca_dev, DECA_STR_STOP, 0);
}

#endif

struct vdec_device * get_selected_decoder(void);
int api_video_get_srcmode(UINT8 *video_Src)
{
    enum TVSystem src_sys;

    //if(vdec_io_control(g_decv_dev, VDEC_IO_GET_MODE,(UINT32)(&src_sys))== RET_SUCCESS)
    if(vdec_io_control(get_selected_decoder(), VDEC_IO_GET_MODE,(UINT32)(&src_sys))== RET_SUCCESS)
    {
        if(src_sys==PAL)
            *video_Src = TV_MODE_PAL;
        else
            *video_Src = TV_MODE_NTSC358;

        return 1;
    }

    return 0;
}

UINT8 api_video_get_tvout(void)
{
	enum TVSystem out_sys;
    struct vpo_io_get_info vpo_info;

	//vpo_ioctl(g_vpo_dev, VPO_IO_GET_OUT_MODE, (UINT32)(&out_sys));
	vpo_ioctl(g_vpo_dev, VPO_IO_GET_INFO, (UINT32)(&vpo_info));

    return tv_mode_to_sys_data_ext(vpo_info.tvsys, vpo_info.bprogressive);
}


static UINT32 m_preview_x, m_preview_y, m_preview_w, m_preview_h;

void api_set_preview_rect(UINT32 x, UINT32 y, UINT32 w, UINT32 h)
{
    m_preview_x = x;
    m_preview_y = y;
    m_preview_w = w;
    m_preview_h = h;
}
void api_subt_show_onoff(BOOL onoff);

#if (ISDBT_CC==1)
void api_isdbtcc_show_onoff(BOOL onoff);
BOOL api_get_isdbtcc_onoff(void);
#endif

void api_preview_play(UINT8 eTVMode)
{
#if (SUBTITLE_ON == 1 )
    if (api_get_subt_onoff())
    {
        api_set_deo_layer(0);
        OSDDrv_ShowOnOff((HANDLE)g_osd_dev2, OSDDRV_OFF);
    }
#endif

#if (ISDBT_CC == 1)
	if (api_get_isdbtcc_onoff())
	{
		api_set_deo_layer(0);
		OSDDrv_ShowOnOff((HANDLE)g_osd_dev2, OSDDRV_OFF);
	}
#endif

#ifdef HDTV_SUPPORT
    if (eTVMode == TV_MODE_720P_60 || eTVMode == TV_MODE_1080I_30 || eTVMode == TV_MODE_1080P_30
        || eTVMode == TV_MODE_1080P_60 || eTVMode == TV_MODE_PAL_M)
        eTVMode = TV_MODE_NTSC443;
	else if(eTVMode == TV_MODE_720P_50 || eTVMode == TV_MODE_1080I_25 || eTVMode == TV_MODE_1080P_25
         || eTVMode == TV_MODE_1080P_50 || eTVMode == TV_MODE_1080P_24 || eTVMode == TV_MODE_PAL_N)
		eTVMode = TV_MODE_PAL;
	else 
#endif
	if(eTVMode == TV_MODE_576P)
		eTVMode = TV_MODE_PAL;
	hde_config_preview_window(m_preview_x, m_preview_y, m_preview_w, m_preview_h, eTVMode == TV_MODE_PAL);

	hde_set_mode(VIEW_MODE_PREVIEW);
    api_set_vpo_dit(TRUE);
#if 0 //def HDTV_SUPPORT
	if (ap_pause_get_status() == PAUSE_STATE)
		ap_send_key_to_control(V_KEY_PAUSE, FALSE);
#endif
}

void api_full_screen_play(void)
{
	hde_set_mode(VIEW_MODE_FULL);
    api_set_vpo_dit(FALSE);
    
#if (SUBTITLE_ON == 1 )
    if (api_get_subt_onoff())
    {
        OSDDrv_ShowOnOff((HANDLE)g_osd_dev2, OSDDRV_ON);
        api_set_deo_layer(1);
    }
#endif	

#if (ISDBT_CC == 1)
	if (api_get_isdbtcc_onoff())
	{
		OSDDrv_ShowOnOff((HANDLE)g_osd_dev2, OSDDRV_ON);
		api_set_deo_layer(1);
	}
#endif	
}

void api_set_vpo_bgcolor(const struct  YCbCrColor *pColor)
{
	vpo_ioctl(g_vpo_dev,VPO_IO_SET_BG_COLOR,(UINT32)pColor);
#if defined(DUAL_VIDEO_OUTPUT) || defined(DUAL_VIDEO_OUTPUT_USE_VCAP)
	vpo_ioctl(g_sd_vpo_dev, VPO_IO_SET_BG_COLOR, (UINT32)pColor);
#endif
}

void api_rgb2yuv(struct YCbCrColor *pbgcolor, UINT8 R, UINT8 G, UINT8 B)
{
 	pbgcolor->uY =0.299*R + 0.587*G + 0.114*B;
 	pbgcolor->uCb =-0.1687*R-0.3313*G+0.5*B+128;
 	pbgcolor->uCr =0.5*R-0.4187*G-0.0813*B+128;
}

void api_yuv2rgb(struct YCbCrColor *pbgcolor, UINT8 *R, UINT8 *G, UINT8 *B)
{
 	*R = (UINT8)(pbgcolor->uY+1.402*(pbgcolor->uCr-128));
 	*G = (UINT8)(pbgcolor->uY-0.34414*(pbgcolor->uCb-128)-0.71414*(pbgcolor->uCr-128));
 	*B = (UINT8)(pbgcolor->uY+1.772*(pbgcolor->uCb-128));
}

void api_set_preview_vpo_color(BOOL enter)
{
	struct YCbCrColor yuvColor;	
 	UINT8 R;
 	UINT8 G;
 	UINT8 B;
 
	if(enter)
	{
//		yuvColor.uY = 185;
//		yuvColor.uCb = 143;
//		yuvColor.uCr = 116;
//		api_yuv2rgb(&yuvColor, &R, &G, &B);
//		libc_printf("RGB: %d, %d, %d\n", R,G,B);
		R = 0x19;//168;
		G = 0x3A;//188;
		B = 0x6A;//211;		
 	}
 	else
 	{
 		R = 16;
 		G = 16;
 		B = 16;	
 	}
 	api_rgb2yuv(&yuvColor, R, G, B);
 	//libc_printf("y=%d, u=%d, v=%d\n",yuvColor.uY,yuvColor.uCb,yuvColor.uCr);
 	api_set_vpo_bgcolor(&yuvColor);
}


UINT32 api_set_deo_layer(UINT32 layer)
{
//    return 0;
    return OSDDrv_IoCtl((HANDLE)g_osd_dev, OSD_IO_SWITCH_DEO_LAYER, !layer);
}

#if defined  SUPPORT_CAS9 || defined  SUPPORT_CAS7
extern OSAL_ID finger_osd_sema_id;
#endif

#if defined(SUPPORT_VMX_STD) || defined(SUPPORT_VMX) //vicky130304
extern OSAL_ID vmx_osd_sema_id;
extern BOOL api_vmx_osd_is_displaying();
#endif

void api_enable_deo_subtitle(BOOL bEnable)
{
#if defined  SUPPORT_CAS9 || defined  SUPPORT_CAS7
	osal_semaphore_capture(finger_osd_sema_id, TMO_FEVR);
	if(!is_fp_displaying())
		OSDDrv_IoCtl((HANDLE)g_osd_dev2, OSD_IO_SET_DEO_AUTO_SWITCH, bEnable);
	osal_semaphore_release(finger_osd_sema_id);
#else
	#if defined(SUPPORT_VMX_STD) || defined(SUPPORT_VMX) //vicky130306#3
	VMX_API_PRINTF("%s-Line-%d\n",__FUNCTION__,__LINE__);
	osal_semaphore_capture(vmx_osd_sema_id, TMO_FEVR);
	VMX_API_PRINTF("%s-Line-%d\n",__FUNCTION__,__LINE__);	
	if(!api_vmx_osd_is_displaying())
	OSDDrv_IoCtl((HANDLE)g_osd_dev2, OSD_IO_SET_DEO_AUTO_SWITCH, bEnable);
	osal_semaphore_release(vmx_osd_sema_id);
	#else
	OSDDrv_IoCtl((HANDLE)g_osd_dev2, OSD_IO_SET_DEO_AUTO_SWITCH, bEnable);
#endif
#endif
}

#if (ISDBT_CC == 1)
void api_enable_deo_isdbtcc(BOOL bEnable)
{
	OSDDrv_IoCtl((HANDLE)g_osd_dev2, OSD_IO_SET_DEO_AUTO_SWITCH, bEnable);
}
#endif

static UINT32 m_win_count;

UINT32 api_inc_wnd_count(void)
{
    m_win_count++;

    api_enable_deo_subtitle(FALSE);
#if (ISDBT_CC == 1)
	api_enable_deo_isdbtcc(FALSE);
#endif
	
    api_set_deo_layer(0);

    //DBG_NUM(m_win_count);
    return m_win_count;
}

UINT32 api_dec_wnd_count(void)
{
    if (m_win_count)
        m_win_count--;

    if (m_win_count == 0)
    {
#if (SUBTITLE_ON == 1 )
        api_enable_deo_subtitle(TRUE);
#if (CC_ON == 1 )
        if (api_get_subt_onoff()|| api_get_atsccc_onoff() )	//vicky20110124
            api_set_deo_layer(1);
#else
        if (api_get_subt_onoff())
            api_set_deo_layer(1);
#endif
#endif

#if (ISDBT_CC == 1)
		api_enable_deo_isdbtcc(TRUE);
		if (api_get_isdbtcc_onoff())
			api_set_deo_layer(1);
#endif
		
    }
#if 0
    else
    {
        DBG_STR("ERROR m_win_count = 0!!!!!!!!");
    }
    DBG_NUM(m_win_count);
#endif
    return m_win_count;
}

/*------------------------------------------------------------

   Other Common functions 
------------------------------------------------------------*/

static BOOL preNtsc = 0;

void api_osd_set_tv_system(BOOL ntsc)
{
	struct OSDRect rect;
	//enum OSDSys uScaleParam;
	
	if(ntsc==preNtsc)
		return;

	OSD_GetRectOnScreen(&rect);
	if(ntsc)
	{
		rect.uTop = OSD_STARTROW_N;
	}
	else
	{
		rect.uTop = OSD_STARTROW_P;
	}
    /*
      It's a big bug to show on osd when switching tv system.
    */
	//OSD_ShowOnOff(OSDDRV_OFF);	
	OSD_SetRectOnScreen(&rect);
	//OSD_ShowOnOff(OSDDRV_ON);
	preNtsc = ntsc;
}

/*struct ui_osd_scale_map
{
    enum TVSystem   tv_sys;
    osd_scale_param scale_param;
};*/

static const osd_scale_param m_osd_scale_map_576[] = 
{
    {PAL, 1,1,1,1/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},
    {PAL_N, 1,1,1,1/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},

    {NTSC, 1,6,1,5/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {NTSC_443, 1,6,1,5/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_60, 1,6,1,5/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_M, 1,6,1,5/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},

    {LINE_720_25, 9, 4, 16, 5/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720 }*/},
    {LINE_720_30, 9, 4, 16, 5/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720}*/},

    {LINE_1080_25, 3,8,8,15/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
    {LINE_1080_30, 3,8,8,15/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
};

static const osd_scale_param m_osd_scale_map_480[] = 
{
    {PAL, 1,5,1,6/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},
    {PAL_N, 1,5,1,6/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},

    {NTSC, 1,1,1,1/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {NTSC_443, 1,1,1,1/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_60, 1,1,1,1/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_M, 1,1,1,1/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},

    {LINE_720_25, 9, 2, 16, 3/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720 }*/},
    {LINE_720_30, 9, 2, 16, 3/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720}*/},

    {LINE_1080_25, 3,12,8,27/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
    {LINE_1080_30, 3,12,8,27/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
};
static const osd_scale_param m_osd_scale_map_720[] = 
{
    {PAL, 16,5,9,4,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},
    {PAL_N, 16,5,9,4,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},

    {NTSC, 16,3,9,2,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {NTSC_443, 16,3,9,2,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_60, 16,3,9,2,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_M, 16,3,9,2,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},

    {LINE_720_25, 1, 1, 1, 1},
    {LINE_720_30, 1, 1, 1, 1},

    {LINE_1080_25, 2,2,3,3,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
    {LINE_1080_30, 2,2,3,3,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
};

static const osd_scale_param m_osd_scale_map_1080[] = 
{
    {PAL, 8,15,3,8,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},
    {PAL_N, 8,15,3,8,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},

    {NTSC, 8,9,3,4,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {NTSC_443, 8,9,3,4,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_60, 8,9,3,4,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_M, 8,9,3,4,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},

    {LINE_720_25, 3, 3, 2, 2,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720 }*/},
    {LINE_720_30, 3, 3, 2, 2,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720}*/},

    {LINE_1080_25, 1,1,1,1,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
    {LINE_1080_30, 1,1,1,1,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
};

#define CLOSE_CAPTION_TEST_OSD
#ifdef CLOSE_CAPTION_TEST_OSD
//1024*576
static const osd_scale_param m_osd_scale_map_1024[] = 
{
    {PAL, 64,1,45,1,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},
    {PAL_N, 64,1,45,1,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},

    {NTSC, 64,6,45,5,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {NTSC_443, 64,6,45,5,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_60, 64,6,45,5,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_M, 64,6,45,5,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},

    {LINE_720_25, 4, 4, 5, 5,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720 }*/},
    {LINE_720_30, 4, 4, 5, 5,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720}*/},

    {LINE_1080_25, 8,8,15,15,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
    {LINE_1080_30, 8,8,15,15,/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
};
#endif


#if ( 0 /*UI_SCREEN_WIDTH == 1280*/ )
static const struct ui_osd_scale_map m_osd_scale_map_720[] = 
{
    {PAL, {16,5,9,4},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},
    {PAL_N, {16,5,9,4},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},

    {NTSC, {16,3,9,2},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {NTSC_443, {16,3,9,2},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_60, {16,3,9,2},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_M, {16,3,9,2},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},

    {LINE_720_25, {1, 1, 1, 1}},
    {LINE_720_30, {1, 1, 1, 1}},

    {LINE_1080_25, {2,2,3,3},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
    {LINE_1080_30, {2,2,3,3},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
};
#elif (0 /*UI_SCREEN_WIDTH_1920 == 1920*/)
static const struct ui_osd_scale_map m_osd_scale_map[] = 
{
    {PAL, {8,15,3,8},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},
    {PAL_N, {8,15,3,8},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 576}*/},

    {NTSC, {8,9,3,4},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {NTSC_443, {8,9,3,4},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_60, {8,9,3,4},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},
    {PAL_M, {8,9,3,4},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 720, 480}*/},

    {LINE_720_25, {3, 3, 2, 2},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720 }*/},
    {LINE_720_30, {3, 3, 2, 2},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1280, 720}*/},

    {LINE_1080_25, {1,1,1,1},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
    {LINE_1080_30, {1,1,1,1},/*{UI_SCREEN_WIDTH, UI_SCREEN_HEIGHT, 1920, 1080}*/},
};
#endif

UINT32 ap_get_osd_scale_param(enum TVSystem eTVMode, INT32 nScreenWidth)
{
    UINT32 i,size_480,size_576,size_720,size_1080,size,size_1024;
    const osd_scale_param  *p_ui_map;

	size = 0;
	p_ui_map = NULL;
    size_720  = ARRAY_SIZE(m_osd_scale_map_720);
    size_1080 = ARRAY_SIZE(m_osd_scale_map_1080);
    size_576 = ARRAY_SIZE(m_osd_scale_map_576);
    size_480 = ARRAY_SIZE(m_osd_scale_map_480);
    size_1024 = ARRAY_SIZE(m_osd_scale_map_1024);

    if (eTVMode == LINE_1080_24 || eTVMode == LINE_1152_ASS || eTVMode == LINE_1080_ASS || eTVMode == LINE_1080_50)
        eTVMode = LINE_1080_25;
    else if (eTVMode == LINE_1080_60)
        eTVMode = LINE_1080_30;

    if(nScreenWidth == 1280)
    {
        size = size_720;
        p_ui_map = m_osd_scale_map_720;
    }
    else if(nScreenWidth == 1920)
    {
        size = size_1080;
        p_ui_map = m_osd_scale_map_1080;    
    }
    else if(nScreenWidth == 720)
    {
        //ASSERT(0);
        size = size_576;
        p_ui_map = m_osd_scale_map_576;
    }
    else if(nScreenWidth == 480)
   	{

	 			size = size_480;
        p_ui_map = m_osd_scale_map_480;
    }
    else if(1024 == nScreenWidth)
    {
        size = size_1024;
        p_ui_map = m_osd_scale_map_1024;
    }
    for (i = 0; i < size; i++)
    {
        if (p_ui_map[i].tv_sys == eTVMode)
        {
            return (UINT32)&(p_ui_map[i]);
        }
    }
    /*
    for (i = 0; i < ARRAY_SIZE(m_osd_scale_map); i++)
    {
        if (m_osd_scale_map[i].tv_sys == eTVMode)
        {
            return (UINT32)&(m_osd_scale_map[i].scale_param);
        }
    }
    */
    // default to PAL
    return (UINT32)&(p_ui_map[0]);
}

#ifndef HDTV_SUPPORT
void api_video_set_tvout(UINT8 tv_mode)
{
	UINT8 TV_Src,TV_Out;
	enum TVSystem tvsys,out_sys;    
	BOOL ntsc;

	tvsys = PAL;
	if(tv_mode!=TV_MODE_AUTO)
	{
		switch(tv_mode)
		{
		case TV_MODE_PAL:
			tvsys = PAL;
			break;
		case TV_MODE_PAL_M:
			tvsys = PAL_M;
			break;
		case TV_MODE_PAL_N:
			tvsys = PAL_N;
			break;
		case TV_MODE_NTSC358:
			tvsys = NTSC;
			break;
		case TV_MODE_SECAM:
			tvsys = SECAM;
			break;
		default:
			tvsys = PAL;
			break;
		}
		vpo_tvsys(g_vpo_dev,tvsys);        
	}
	
	if(tvsys == SECAM)
	{
		struct vp_io_reg_dac_para dac_reg_para;
		
		vpo_ioctl(g_vpo_dev,VPO_IO_UNREG_DAC,VDAC_USE_CVBS_TYPE);

		dac_reg_para.eDacType = SECAM_CVBS1;
		dac_reg_para.DacInfo.bEnable = 1;
		dac_reg_para.DacInfo.tDacIndex.uDacFirst    = CVBS_DAC;
		dac_reg_para.DacInfo.eVGAMode = VGA_NOT_USE;
		dac_reg_para.DacInfo.bProgressive = FALSE;
		vpo_ioctl(g_vpo_dev, VPO_IO_REG_DAC,(UINT32)(&dac_reg_para));
	}

	vpo_ioctl(g_vpo_dev, VPO_IO_GET_OUT_MODE, (UINT32)(&out_sys));
	if(out_sys == NTSC||out_sys == PAL_M||out_sys == PAL_60||out_sys == NTSC_443)
		ntsc = TRUE;
	else
		ntsc = FALSE;
	api_osd_set_tv_system(ntsc);
}

#else	// HDTV_SUPPORT

#ifndef TRUE_COLOR_HD_OSD//(OSD_MAX_WIDTH != 1280) // 720x576
void set_osd_pos_for_tv_system(enum TVSystem eTVMode)
{
	enum	OSDSys	eOSDSys = OSD_PAL;
    UINT32 cmd = OSD_VSCALE_OFF;
#ifndef	P2N_SCALE_IN_NORMAL_PLAY

    if (eTVMode == LINE_1080_24 || eTVMode == LINE_1152_ASS || eTVMode == LINE_1080_ASS || eTVMode == LINE_1080_50)
        eTVMode = LINE_1080_25;
    else if (eTVMode == LINE_1080_60)
        eTVMode = LINE_1080_30;

	if((PAL == eTVMode) || (PAL_N == eTVMode))
	{
		eOSDSys = OSD_PAL;
		api_osd_set_tv_system(FALSE);
		OSD_Scale(OSD_VSCALE_OFF, &eOSDSys);
	}
	else if(LINE_1080_25 == eTVMode)
	{
		api_osd_set_tv_system(FALSE);
		OSD_Scale(OSD_OUTPUT_1080, OSD_SOURCE_PAL);
        cmd = OSD_OUTPUT_1080;
	}	
	else if(LINE_1080_30 == eTVMode)
	{
   		eOSDSys = OSD_NTSC;
		api_osd_set_tv_system(TRUE);
		OSD_Scale(OSD_OUTPUT_1080, OSD_SOURCE_NTSC);
        cmd = OSD_OUTPUT_1080;
	}	
	else if(LINE_720_25 == eTVMode)
	{
		api_osd_set_tv_system(FALSE);
		OSD_Scale(OSD_OUTPUT_720, OSD_SOURCE_PAL);
        cmd = OSD_OUTPUT_720;
	}
	else if(LINE_720_30 == eTVMode)
	{
   		eOSDSys = OSD_NTSC;
		api_osd_set_tv_system(TRUE);
		OSD_Scale(OSD_OUTPUT_720, OSD_SOURCE_NTSC);
        cmd = OSD_OUTPUT_720;
	}
	else// if((NTSC == eTVMode) || (NTSC_443 == eTVMode) || (PAL_M == eTVMode))
	{
		eOSDSys = OSD_NTSC;
		api_osd_set_tv_system(TRUE);
		OSD_Scale(OSD_VSCALE_OFF, (UINT32)&eOSDSys);
	}
    if (cmd == OSD_VSCALE_OFF)
        OSDDrv_Scale((HANDLE)g_osd_dev2, OSD_VSCALE_OFF, (UINT32)&eOSDSys);
    else
    {
        OSDDrv_Scale((HANDLE)g_osd_dev2, OSD_VSCALE_TTX_SUBT, (UINT32)&eOSDSys);
    }
#else
	if((PAL == eTVMode) || (PAL_N == eTVMode))
	{
		eOSDSys = OSD_PAL;
		OSD_Scale(OSD_VSCALE_OFF, &eOSDSys);
	}
	else// if(NTSC == eTVMode)
	{
		eOSDSys = OSD_NTSC;
		OSD_Scale(OSD_VSCALE_OFF, &eOSDSys);
	}
#endif
}
#else

void set_osd_pos_for_tv_system(enum TVSystem eTVMode)
{
    if (eTVMode == LINE_1080_24 || eTVMode == LINE_1152_ASS || eTVMode == LINE_1080_ASS || eTVMode == LINE_1080_50)
        eTVMode = LINE_1080_25;
    else if (eTVMode == LINE_1080_60)
        eTVMode = LINE_1080_30;

	if((PAL == eTVMode) || (PAL_N == eTVMode))
	{
		api_osd_set_tv_system(FALSE);
	}
	else if(LINE_1080_25 == eTVMode)
	{
		api_osd_set_tv_system(FALSE);
	}
	else if(LINE_1080_30 == eTVMode)
	{
		api_osd_set_tv_system(TRUE);
	}
	else if(LINE_720_25 == eTVMode)
	{
		api_osd_set_tv_system(FALSE);
	}
	else if(LINE_720_30 == eTVMode)
	{
		api_osd_set_tv_system(TRUE);
	}
    else
    {
		api_osd_set_tv_system(TRUE);
    }
    UINT32 param = ap_get_osd_scale_param(eTVMode, UI_SCREEN_WIDTH);
    pcosd_scale_param pscalemp = (pcosd_scale_param )param;
    if(pscalemp->h_div > pscalemp->h_mul)
    {
        OSDDrv_Scale((HANDLE)g_osd_dev,OSD_SET_SCALE_MODE,OSD_SCALE_FILTER);//OSD_SCALE_DUPLICATE);
    }
    else
    {
        if (sys_ic_get_chip_id() == ALI_S3602)
            OSDDrv_Scale((HANDLE)g_osd_dev,OSD_SET_SCALE_MODE,OSD_SCALE_DUPLICATE);
        else
            OSDDrv_Scale((HANDLE)g_osd_dev,OSD_SET_SCALE_MODE,OSD_SCALE_FILTER); // S3602F always use filter mode
    }
    OSDDrv_Scale((HANDLE)g_osd_dev, OSD_SCALE_WITH_PARAM, param);
    param = ap_get_osd_scale_param(eTVMode, UI_SCREEN_WIDTH2);

#if defined  SUPPORT_CAS9 || defined  SUPPORT_CAS7
	osal_semaphore_capture(finger_osd_sema_id, TMO_FEVR);
	if(!is_fp_displaying())
    	OSDDrv_Scale((HANDLE)g_osd_dev2, OSD_SCALE_WITH_PARAM, param);
	osal_semaphore_release(finger_osd_sema_id);
#else
	#if defined(SUPPORT_VMX_STD) || defined(SUPPORT_VMX)	//vicky130304
	VMX_API_PRINTF("%s-Line-%d\n",__FUNCTION__,__LINE__);
	osal_semaphore_capture(vmx_osd_sema_id, TMO_FEVR);
	VMX_API_PRINTF("%s-Line-%d\n",__FUNCTION__,__LINE__);
	if(!api_vmx_osd_is_displaying())
	OSDDrv_Scale((HANDLE)g_osd_dev2, OSD_SCALE_WITH_PARAM, param);
	osal_semaphore_release(vmx_osd_sema_id);
	#else
	OSDDrv_Scale((HANDLE)g_osd_dev2, OSD_SCALE_WITH_PARAM, param);
#endif
#endif

}
#endif
/*
void api_video_set_tvout(UINT8 tv_mode)
{ 
	sys_data_set_TV_mode(tv_mode);
#if 0
	BOOL progressive;
	enum TVSystem tvsys;   

	if (tv_mode != TV_MODE_AUTO)
	{
		tvsys = sys_data_to_tv_mode(tv_mode);
		progressive = sys_data_is_progressive(tv_mode);
		vpo_tvsys_ex(g_vpo_dev, tvsys, progressive);
		osal_task_sleep(50);

		if(tvsys == SECAM)
		{
			struct vp_io_reg_dac_para dac_reg_para;
			
			vpo_ioctl(g_vpo_dev,VPO_IO_UNREG_DAC,VDAC_USE_CVBS_TYPE);

			dac_reg_para.eDacType = SECAM_CVBS1;
			dac_reg_para.DacInfo.bEnable = 1;
			dac_reg_para.DacInfo.tDacIndex.uDacFirst    = CVBS_DAC;
			dac_reg_para.DacInfo.eVGAMode = VGA_NOT_USE;
			dac_reg_para.DacInfo.bProgressive = FALSE;
			vpo_ioctl(g_vpo_dev, VPO_IO_REG_DAC,(UINT32)(&dac_reg_para));
		}
		
		set_osd_pos_for_tv_system(tvsys);
	}
#endif
}
*/
#endif

#ifdef PARENTAL_SUPPORT
void api_lock_channel(UINT32 ch_id)
{
	//vpo_win_onoff((struct vpo_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_DIS),FALSE);
	//snd_io_control((struct snd_device*)dev_get_by_type(NULL, HLD_DEV_TYPE_SND), SND_CC_MUTE, 0);
	//UIChChgLockProg(ch_id,TRUE);
	//disable_process_cc(TRUE);//DON'T SHOW CC and clear
#if (SUBTITLE_ON == 1) 	
	api_subt_show_onoff(FALSE);
#endif
	#if (ISDBT_CC == 1)
	api_isdbtcc_show_onoff(FALSE);
	#endif
}
#endif

void api_osd2_set_tv_system(BOOL ntsc)
{
	struct OSDRect tOpenRect;

	tOpenRect.uLeft = (UI_SCREEN_WIDTH - OSD_MAX_WIDTH)>>1;
	tOpenRect.uWidth = OSD_MAX_WIDTH;
	tOpenRect.uHeight = OSD_MAX_HEIGHT;

    if (ntsc)
        tOpenRect.uTop = OSD_STARTROW_N;
    else
	    tOpenRect.uTop = OSD_STARTROW_P;

    OSDDrv_SetRegionPos((HANDLE)g_osd_dev2, 0, &tOpenRect);
}

void api_osd2_scale(UINT8 uScaleCmd, UINT32 uScaleParam)
{
	OSDDrv_Scale((HANDLE)g_osd_dev2, uScaleCmd, uScaleParam);
}

#ifndef TRUE_COLOR_HD_OSD //(OSD_MAX_WIDTH != 1280) // 720x576
void set_osd2_pos_for_tv_system(enum TVSystem eTVMode)
{
	enum	OSDSys	eOSDSys = OSD_PAL;
    UINT32 cmd = OSD_VSCALE_OFF;

    if (eTVMode == LINE_1080_24 || eTVMode == LINE_1152_ASS || eTVMode == LINE_1080_ASS || eTVMode == LINE_1080_50)
        eTVMode = LINE_1080_25;
    else if (eTVMode == LINE_1080_60)
        eTVMode = LINE_1080_30;

	if((PAL == eTVMode) || (PAL_N == eTVMode))
	{
		eOSDSys = OSD_PAL;
		api_osd2_set_tv_system(FALSE);
		api_osd2_scale(OSD_VSCALE_OFF, (UINT32)&eOSDSys);
	}
	else if(LINE_1080_25 == eTVMode)
	{
		api_osd2_set_tv_system(FALSE);
		api_osd2_scale(OSD_OUTPUT_1080, OSD_SOURCE_PAL);
        cmd = OSD_OUTPUT_1080;
	}
	else if(LINE_1080_30 == eTVMode)
	{
   		eOSDSys = OSD_NTSC;
		api_osd2_set_tv_system(TRUE);
		api_osd2_scale(OSD_OUTPUT_1080, OSD_SOURCE_NTSC);
        cmd = OSD_OUTPUT_1080;
	}
	else if(LINE_720_25 == eTVMode)
	{
		api_osd2_set_tv_system(FALSE);
		api_osd2_scale(OSD_OUTPUT_720, OSD_SOURCE_PAL);
        cmd = OSD_OUTPUT_720;
	}
	else if(LINE_720_30 == eTVMode)
	{
   		eOSDSys = OSD_NTSC;
		api_osd2_set_tv_system(TRUE);
		api_osd2_scale(OSD_OUTPUT_720, OSD_SOURCE_NTSC);
        cmd = OSD_OUTPUT_720;
	}
	else// if((NTSC == eTVMode) || (NTSC_443 == eTVMode) || (PAL_M == eTVMode))
	{
		eOSDSys = OSD_NTSC;
		api_osd2_set_tv_system(TRUE);
		api_osd2_scale(OSD_VSCALE_OFF, (UINT32)&eOSDSys);
	}
}
#else
void set_osd2_pos_for_tv_system(enum TVSystem eTVMode)
{

    if (eTVMode == LINE_1080_24 || eTVMode == LINE_1152_ASS || eTVMode == LINE_1080_ASS || eTVMode == LINE_1080_50)
        eTVMode = LINE_1080_25;
    else if (eTVMode == LINE_1080_60)
        eTVMode = LINE_1080_30;

	if((PAL == eTVMode) || (PAL_N == eTVMode))
	{
		api_osd2_set_tv_system(FALSE);
	}
	else if(LINE_1080_25 == eTVMode)
	{
		api_osd2_set_tv_system(FALSE);
	}
	else if(LINE_1080_30 == eTVMode)
	{
		api_osd2_set_tv_system(TRUE);
	}
	else if(LINE_720_25 == eTVMode)
	{
		api_osd2_set_tv_system(FALSE);
	}
	else if(LINE_720_30 == eTVMode)
	{
		api_osd2_set_tv_system(TRUE);
	}
    else
    {
		api_osd2_set_tv_system(TRUE);
    }

    UINT32 param = ap_get_osd_scale_param(eTVMode, UI_SCREEN_WIDTH2);
    OSDDrv_Scale((HANDLE)g_osd_dev2, OSD_SCALE_WITH_PARAM, param);
}
#endif


ID api_start_timer(char* name, UINT32 interval, OSAL_T_TIMER_FUNC_PTR handler)
{
	OSAL_T_CTIM 	t_dalm;
	ID				alarmID;

	t_dalm.callback = handler;
	t_dalm.type = TIMER_ALARM;
	t_dalm.time  = interval;
	
	alarmID = osal_timer_create(&t_dalm);
	if(OSAL_INVALID_ID != alarmID)
	{
		//libc_printf("----------------start %s timer succeed\n", name);
		return alarmID;
		
	}
	else
	{
		//libc_printf("----------------start %s timer failed\n",name);
		return OSAL_INVALID_ID;
		
	}
}

ID api_start_cycletimer(char* name, UINT32 interval, OSAL_T_TIMER_FUNC_PTR handler)
{
	OSAL_T_CTIM 	t_dalm;
	ID				alarmID;

	t_dalm.callback = handler;
	t_dalm.type = OSAL_TIMER_CYCLE;
	t_dalm.time  = interval;
	
	alarmID = osal_timer_create(&t_dalm);
	if(OSAL_INVALID_ID != alarmID)
	{
		//libc_printf("----------------start %s timer succeed\n", name);
		osal_timer_activate(alarmID, 1);	
		return alarmID;
	}
	else
	{
		//libc_printf("----------------start %s timer failed\n",name);
		return OSAL_INVALID_ID;
	}
}


void api_stop_timer(ID* pTimerID)
{
	ID timerID = *pTimerID;
	if(OSAL_INVALID_ID != timerID)
		osal_timer_delete(timerID);
	*pTimerID = OSAL_INVALID_ID;	
}


UINT8 api_ttxsub_getlang(struct t_ttx_lang *lang_ttx_list,struct t_subt_lang* lang_sub_list,UINT8 select,UINT8 lang_num)
{
	UINT8 i;
	UINT8 stream_lang_num,stream_langmucode_num;
	struct t_ttx_lang 	*lang_txt;
	struct t_subt_lang	*lang_sub;
	UINT8 lang_code[3],lang_codem[3],*code;
	extern char *stream_iso_639lang_abbr[];
	extern char *iso_639lang_multicode[][2];
	
	stream_lang_num = get_stream_lang_cnt();
	stream_langmucode_num = get_stream_langm_cnt();
	
	
	if(lang_num==0)
		return 0xFF;
	if(lang_ttx_list == NULL && lang_sub_list==NULL)
		return 0xFF;
	
	if(lang_num == 1)
		return 0;
	if(select < stream_lang_num)
	{
		MEMCPY(lang_code,stream_iso_639lang_abbr[select],3);
		MEMCPY(lang_codem,lang_code,3);
		for(i=0;i<stream_langmucode_num;i++)
		{
			if(MEMCMP(iso_639lang_multicode[i][0],lang_code,3) == 0)
			{
				MEMCPY(lang_codem,iso_639lang_multicode[i][1],3);
				break;
			}
		}
	}
	else
		return 0;
	
	for(i=0;i<lang_num;i++)
	{
		if(lang_ttx_list != NULL)
		{
			lang_txt = &lang_ttx_list[i];
			
			code = lang_txt->lang;
		}
		else
		{
			lang_sub = &lang_sub_list[i];
			code = lang_sub->lang;
		}
#ifdef SUPPORT_FRANCE_HD
		if(MEMCMP("qaa",code,3) == 0)
		{
			return i;

		}
#endif		
		if(MEMCMP(lang_code,code,3) == 0
			|| MEMCMP(lang_codem,code,3) == 0)
			return i;
	}

	return 0;
}

extern struct vdec_device *g_decv_avc_dev;


#if (TTX_ON ==1)
static BOOL m_ttx_onoff=FALSE;
BOOL api_get_ttx_onoff(void)
{
	    return m_ttx_onoff;
}
void api_ttx_show_onoff(BOOL onoff)
{
    if (!onoff)
        api_set_deo_layer(0);

    TTXEng_ShowOnOff(onoff);

    if (onoff)
        api_set_deo_layer(1);
    m_ttx_onoff=onoff;
}
#endif

#if (SUBTITLE_ON == 1 )
static BOOL m_subtilte_onoff = FALSE;
static BOOL m_atsccc_onoff=FALSE; //vicky20110124
BOOL api_get_subt_onoff(void)
{
    return m_subtilte_onoff;
}

#if (CC_ON == 1 )
BOOL api_get_atsccc_onoff(void) //vicky20110124
{
    return m_atsccc_onoff;
}
#endif
void api_subt_show_onoff(BOOL onoff)
{
	//vicky130306#3
	#if defined(SUPPORT_VMX_STD) || defined(SUPPORT_VMX)
	if(api_vmx_osd_is_displaying())
	{
		VMX_API_PRINTF("%s force skip\n",__FUNCTION__);
		return;
	}
	#endif

    if (!onoff)
        api_set_deo_layer(0);
    
#if 0 //defined (_MHEG5_V20_ENABLE_)
        if (!m_subtilte_onoff && onoff)
        {
            struct t_subt_lang *sub_lang=NULL;
            UINT8 number = 0;
            subt_get_language(&sub_lang, &number);
            if (number >0)
            {
                MHEG5_ReceiverStopApplications();
                MHEG5_OSDExit();
                api_set_deo_layer(1);
            }
        }
#endif

    subt_show_onoff(onoff);

#if 0 //defined (_MHEG5_V20_ENABLE_)
        if (m_subtilte_onoff && !onoff)
        {
            if (!GetPauseState())
            {
                MHEG5_OSDEnter();
                MHEG5_ReceiverStartApplications(si_get_cur_channel());
            }
        }
#endif

    if (onoff)
        api_set_deo_layer(1);

    m_subtilte_onoff = onoff;
}
#endif
#if (CC_ON == 1 )
//vicky20110124
void api_atsccc_show_onoff(BOOL onoff)
{
	if (!onoff)
      		api_set_deo_layer(0);
	atsc_cc_show_onoff(onoff);
	if (onoff)
		api_set_deo_layer(1);
    m_atsccc_onoff = onoff;
}
#endif

#if (ISDBT_CC==1)
	static BOOL m_isdbtcc_onoff=FALSE;
	BOOL api_get_isdbtcc_onoff(void)
	{
	    return m_isdbtcc_onoff;
	}

	void api_isdbtcc_show_onoff(BOOL onoff)
	{
        if(TRUE == onoff)
        {
            if(TRUE == isdbtcc_is_available())
            {
                isdbtcc_show_onoff(TRUE);
                api_set_deo_layer(1);
                m_isdbtcc_onoff = TRUE;
            }
            return;    
        }
       
        isdbtcc_show_onoff(FALSE);
        api_set_deo_layer(0);
		    m_isdbtcc_onoff = FALSE;
	}
#endif

#ifdef TTX_EPG_SHARE_MEM
void api_ttx_epg_share_epg_on(void)
{
    UINT16 cur_channel = 0;
    UINT32 dmx_id = 0;
    struct ts_route_info l_ts_route;
    struct dmx_device *dmx = NULL;
    P_NODE 	p_node;
    
    extern void ap_epg_call_back(UINT32 tp_id, UINT16 service_id, UINT8 event_type);
    ttx_enable(FALSE);
    epg_init(SIE_EIT_WHOLE_TP, (UINT8*)__MM_EPG_BUFFER_START/*buffer*/, __MM_EPG_BUFFER_LEN, ap_epg_call_back);

    cur_channel = sys_data_get_cur_group_cur_mode_channel();
    get_prog_at(cur_channel, &p_node);


    if (ts_route_get_by_type(TS_ROUTE_MAIN_PLAY, NULL, &l_ts_route) == RET_SUCCESS)
    {
        dmx_id = l_ts_route.dmx_id;
    }
    dmx = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_id);

    #ifdef _INVW_JUICE   
    epg_on_by_inview(dmx, p_node.sat_id,p_node.tp_id,p_node.prog_number, 0);
    #else
    epg_on_ext(dmx, p_node.sat_id,p_node.tp_id,p_node.prog_number);
    #endif
}
#endif


#if defined  SUPPORT_CAS9 || defined  SUPPORT_CAS7
enum OSD_MODE api_osd_mode_change_ex(enum OSD_MODE mode)
{/*SUBTITLE_ON,TTX_ON macro total a shit,with all project open,failure if closed*/
	enum OSD_MODE pre_mode;
	SYSTEM_DATA* sys_data;
	static UINT8 current_sub_mode = 0xFF;
    struct t_subt_lang	*sublang_list;
    UINT8 lang_num,sel_lang;
    static UINT8 pre_sel_lang=0xFF;
    
	#if (ISDBT_CC == 1)
	struct t_isdbtcc_lang*cclanglst;
	UINT8 bLangNum,bCcLang;
	#endif
	
	sys_data = sys_data_get();	
	pre_mode = g_second_osd_mode;

    sel_lang = 0xFF;
#if (SUBTITLE_ON == 1)
	subt_get_language(&sublang_list,&lang_num);
	sel_lang = api_ttxsub_getlang(NULL,sublang_list,sys_data->lang.sub_lang,lang_num);
#endif

#if (ISDBT_CC == 1)
	isdbtcc_get_language(&cclanglst, &bLangNum);
	bCcLang=sys_data->osd_set.subtitle_lang; 
#endif

	if(mode == pre_mode && sel_lang == pre_sel_lang)//if find subt lang change, redo osd mode change
	{
		return pre_mode;
	}

    pre_sel_lang = sel_lang;
	if(OSD_MSG_POPUP == mode)
	{
		UINT8* pal_data;
		struct OSDPara	tOpenPara;
		struct OSDRect tOpenRect,r;
		enum TVSystem tvsys;
		struct osd_device *osd_dev;

#if (SUBTITLE_ON == 1 )
		if( pre_mode == OSD_SUBTITLE && current_sub_mode == 0)
		{
			api_subt_show_onoff(FALSE);
		}
#endif
#if (TTX_ON ==1)
		else if((pre_mode == OSD_SUBTITLE && current_sub_mode == 1) || pre_mode == OSD_TELETEXT)
		{
			TTXEng_SetInitLang(0xFF);//for exit TTXEng
			api_ttx_show_onoff(FALSE);
			//modify for TTX and EPG share buffer 2011 10 10
			#ifdef TTX_EPG_SHARE_MEM
			extern void ap_epg_call_back(UINT32 tp_id, UINT16 service_id, UINT8 event_type);
		        ttx_enable(FALSE);
			epg_init(SIE_EIT_WHOLE_TP, (UINT8*)__MM_EPG_BUFFER_START/*buffer*/, __MM_EPG_BUFFER_LEN, ap_epg_call_back);
			#endif//modify end
		}
#endif
#if (CC_ON == 1 )
		if(pre_mode == OSD_SUBTITLE )
		{
			if(TRUE==api_get_atsccc_onoff())	//vicky20110216
				api_atsccc_show_onoff(FALSE);		
			#ifdef CC_BY_VBI
				cc_vbi_show_on(FALSE);
            #endif
		}
#endif

#if (ISDBT_CC == 1)
		if(pre_mode == OSD_SUBTITLE )
		{
			api_isdbtcc_show_onoff(FALSE);
		}
#endif

		vpo_ioctl(g_vpo_dev, VPO_IO_GET_OUT_MODE, (UINT32)(&tvsys));

#if (COLOR_N==4)
		tOpenPara.eMode = OSD_4_COLOR;
#elif (COLOR_N==16)
		tOpenPara.eMode = OSD_16_COLOR;
#elif (COLOR_N==256)
		tOpenPara.eMode = OSD_256_COLOR;
#endif
		tOpenPara.uGAlphaEnable = 0;
		tOpenPara.uGAlpha = 0x0f;

		tOpenRect.uLeft = (720 - OSD_MAX_WIDTH)>>1;
		tOpenRect.uWidth = OSD_MAX_WIDTH;
		tOpenRect.uTop = OSD_STARTROW_P;
		tOpenRect.uHeight = OSD_MAX_HEIGHT;

		r.uLeft = 0;
		r.uTop = 0;
		r.uWidth = OSD_MAX_WIDTH;
		r.uHeight = OSD_MAX_HEIGHT;

		osd_dev = g_osd_dev2;
		OSDDrv_ShowOnOff((HANDLE)osd_dev,OSDDRV_OFF);
		OSDDrv_Close((HANDLE)osd_dev);
		OSDDrv_Open((HANDLE)osd_dev, &tOpenPara);
		osal_task_sleep(20);
		OSDDrv_CreateRegion((HANDLE)osd_dev, 0, &(tOpenRect), NULL);
		OSDDrv_RegionFill((HANDLE)osd_dev,0,&r, OSD_TRANSPARENT_COLOR);

        set_osd2_pos_for_tv_system(tvsys);

		/*Set pallette,for the second layer osd,it no need transparent*/
		pal_data = (UINT8*)OSD_GetRscPallette(0x4080 | system_config.osd_set.pallete);
		OSDDrv_SetPallette((HANDLE)osd_dev, pal_data, COLOR_N, OSDDRV_YCBCR);
		//OSDDrv_ShowOnOff((HANDLE)osd_dev,OSDDRV_ON);
		g_second_osd_mode = OSD_MSG_POPUP;
	}
	else if(mode == OSD_NO_SHOW)
	{
#if (CC_ON == 1 )
		if(	(pre_mode==OSD_SUBTITLE)	&&	(TRUE==api_get_atsccc_onoff())	)
		{
			api_atsccc_show_onoff(FALSE);		
			
		}	
		#ifdef CC_BY_VBI
			if(pre_mode==OSD_SUBTITLE)
				cc_vbi_show_on(FALSE);
		#endif
#endif		
#if (SUBTITLE_ON == 1 )
		if( pre_mode == OSD_SUBTITLE && current_sub_mode == 0)
		{
			api_subt_show_onoff(FALSE);
		}
#endif	
#if (TTX_ON ==1)
		else if((pre_mode == OSD_SUBTITLE && current_sub_mode == 1) || pre_mode == OSD_TELETEXT)
		{
			TTXEng_SetInitLang(0xFF);//for exit TTXEng
			api_ttx_show_onoff(FALSE);			
		}
		else
#endif	
			if(pre_mode == OSD_MSG_POPUP)
		{
			OSDDrv_ShowOnOff((HANDLE)g_osd_dev2,OSDDRV_OFF);
		}
#if (ISDBT_CC == 1)
		if(pre_mode == OSD_SUBTITLE )
		{
			api_isdbtcc_show_onoff(FALSE);
		}
		else if(pre_mode == OSD_MSG_POPUP)
		{
			OSDDrv_ShowOnOff((HANDLE)g_osd_dev2,OSDDRV_OFF);
		}
#endif
		g_second_osd_mode = OSD_NO_SHOW;
	}
	else if(mode == OSD_SUBTITLE)
	{
		#if(CC_ON==1) //vicky20110216
		#ifdef CC_BY_OSD
		if(sys_data->osd_set.cc_display==1)
		{
			//if(get_dtv_cs_number()||get_cc_control_byte())
				api_atsccc_show_onoff(TRUE);
		}
		else
		{
			if(TRUE==api_get_atsccc_onoff())	//vicky20110216
				api_atsccc_show_onoff(FALSE); 
		}
		#endif
		#ifdef CC_BY_VBI			
			cc_vbi_show_on(TRUE);
		#endif
		
		#endif
		
		if(sys_data->osd_set.subtitle_display == 1)
		{
			struct t_ttx_lang *ttxlang_list;
			UINT8 lang_numttx,sub_mode;

			sub_mode = 0;

#if (TTX_ON ==1)			
			if(sel_lang == 0xFF)
			{	
				sub_mode = 1;
				TTXEng_GetSubtLang(&ttxlang_list, &lang_num);
				sel_lang = api_ttxsub_getlang(ttxlang_list,NULL,sys_data->lang.sub_lang,lang_num);				
			}
#endif
			if(sys_data->osd_set.subtitle_lang != SUBTITLE_LANGUAGE_INVALID)
			{
				subt_get_language(&sublang_list,&lang_num);
				TTXEng_GetSubtLang(&ttxlang_list, &lang_numttx);
				
				if(((lang_num + lang_numttx) > 0) && (sys_data->osd_set.subtitle_lang < (lang_num + lang_numttx)))
				{
					if(lang_numttx>0 && sys_data->osd_set.subtitle_lang <lang_numttx)
					{
						sub_mode = 1;/*ttx-subtitle*/
						sel_lang = sys_data->osd_set.subtitle_lang;
					}
					else if((lang_num>0) && (sys_data->osd_set.subtitle_lang <(lang_num + lang_numttx)))
					{
						sub_mode = 0;/*normal-subtitle*/
						sel_lang = (sys_data->osd_set.subtitle_lang - lang_numttx);
					}
				}
				else
				{		
					PRINTF("NO SUBTITLE DATA.\n");
				}
					
			}
			
			if(sel_lang != 0XFF)/*subt languages exist*/
			{
				if(sub_mode == 0)
				{
#if (CC_ON ==1)
	#ifdef CC_BY_OSD
		api_atsccc_show_onoff(FALSE);	//vicky20110216
    #endif
#endif				

#if (TTX_ON ==1)
					api_ttx_show_onoff(FALSE);
#endif

#if (SUBTITLE_ON == 1)
					api_subt_show_onoff(TRUE);
					subt_set_language(sel_lang);
#endif				
				}
				else
				{
#if (CC_ON ==1)
	#ifdef CC_BY_OSD
		api_atsccc_show_onoff(FALSE);	//vicky20110216
    #endif
#endif				
				
#if (SUBTITLE_ON == 1 )
					api_subt_show_onoff(FALSE);
#endif

#if (TTX_ON ==1)
//modify for TTX and EPG share buffer 2011 10 10
#ifdef TTX_EPG_SHARE_MEM
					epg_off();
                    epg_reset();
					epg_release();
				        ttx_enable(TRUE);
#endif//modify end
					api_ttx_show_onoff(TRUE);
					TTXEng_SetSubtLang(sel_lang);
#endif
				}
			}
			
#if (ISDBT_CC == 1)
		//libc_printf("\nOsd mode change and lang num(%d)",bLangNum);
		api_isdbtcc_show_onoff(TRUE);
		if(	(SUBTITLE_LANGUAGE_INVALID==bCcLang)  || (0>=bLangNum) || (bLangNum<=bCcLang))
		{
			//api_isdbtcc_show_onoff(FALSE);
		}
		else
		{			
			isdbtcc_set_language(bCcLang);				
		}
#endif	
			current_sub_mode = sub_mode;
		}
		else
		{
			/*Even subt off,we should still close ttx*/	
#if (TTX_ON ==1)
				api_ttx_show_onoff(FALSE);
#endif
		}
		g_second_osd_mode = OSD_SUBTITLE;
	}
	else if(mode == OSD_TELETEXT)
	{
#if (TTX_ON ==1)
		PRINTF("TELETEXT\n");
#if (SUBTITLE_ON == 1 )
		api_subt_show_onoff(FALSE);

#endif
#if (CC_ON ==1)
	#ifdef CC_BY_OSD
		api_atsccc_show_onoff(FALSE);	//vicky20110216
        #endif
#endif	
		api_ttx_show_onoff(TRUE);
		g_second_osd_mode = OSD_TELETEXT;
#endif
	}
	else if(mode == OSD_INVALID_MODE)
		g_second_osd_mode = OSD_INVALID_MODE;		

	return pre_mode;
}

enum OSD_MODE api_osd_mode_change(enum OSD_MODE mode)
{
	enum OSD_MODE ret_mode;
	SYSTEM_DATA* sys_data;

	sys_data = sys_data_get();	
	ret_mode = g_second_osd_mode;

	osal_semaphore_capture(finger_osd_sema_id, TMO_FEVR);
	if(!is_fp_displaying())
		ret_mode = api_osd_mode_change_ex(mode);
	osal_semaphore_release(finger_osd_sema_id);
	return ret_mode;
}
#else
enum OSD_MODE api_osd_mode_change(enum OSD_MODE mode)
{/*SUBTITLE_ON,TTX_ON macro total a shit,with all project open,failure if closed*/
	enum OSD_MODE pre_mode;
	SYSTEM_DATA* sys_data;
	static UINT8 current_sub_mode = 0xFF;
    struct t_subt_lang	*sublang_list;
    UINT8 lang_num,sel_lang;
    static UINT8 pre_sel_lang=0xFF;
    struct t_ttx_lang *ttxlang_list;
    UINT8 b_ttx_lang = 0 ;
    
#if (ISDBT_CC == 1)
	struct t_isdbtcc_lang*cclanglst;
	UINT8 bLangNum,bCcLang;
#endif
	    
	sys_data = sys_data_get();	
	pre_mode = g_second_osd_mode;

#if ((SUBTITLE_ON == 1 )||(TTX_ON ==1))   
   #if(defined(MULTI_CAS) && defined(SUPPORT_CAS_A))
	if(is_fp_displaying() == TRUE)
		return pre_mode;
   #endif
#endif   	

    sel_lang = 0xFF;
#if (SUBTITLE_ON == 1)
	subt_get_language(&sublang_list,&lang_num);
	sel_lang = api_ttxsub_getlang(NULL,sublang_list,sys_data->lang.sub_lang,lang_num);
    b_ttx_lang = 0;
#endif

#if (TTX_ON ==1)
    if(sel_lang == 0xFF)
    {
        TTXEng_GetSubtLang(&ttxlang_list, &lang_num);
    	sel_lang = api_ttxsub_getlang(ttxlang_list,NULL,sys_data->lang.sub_lang,lang_num);
        b_ttx_lang = 1;
    }
#endif
    
#if (ISDBT_CC == 1)
        isdbtcc_get_language(&cclanglst, &bLangNum);
        bCcLang=sys_data->osd_set.subtitle_lang; 
#endif    

	if(mode == pre_mode && sel_lang == pre_sel_lang)//if find subt lang change, redo osd mode change
	{
		return pre_mode;
	}

	#if defined(SUPPORT_VMX_STD) || defined(SUPPORT_VMX)	//vicky130304
	{
		if(api_vmx_osd_is_displaying())
		{			
			return pre_mode;
		}
			VMX_API_PRINTF("%s-Line-%d\n",__FUNCTION__,__LINE__);
			osal_semaphore_capture(vmx_osd_sema_id, TMO_FEVR);
			VMX_API_PRINTF("%s-Line-%d\n",__FUNCTION__,__LINE__);
	}
	#endif

    pre_sel_lang = sel_lang;
	if(OSD_MSG_POPUP == mode)
	{
		UINT8* pal_data;
		struct OSDPara	tOpenPara;
		struct OSDRect tOpenRect,r;
		enum TVSystem tvsys;
		struct osd_device *osd_dev;

#if (SUBTITLE_ON == 1 )
		if( pre_mode == OSD_SUBTITLE && current_sub_mode == 0)
		{
			api_subt_show_onoff(FALSE);
		}
#endif
#if (TTX_ON ==1)
		else if((pre_mode == OSD_SUBTITLE && current_sub_mode == 1) || pre_mode == OSD_TELETEXT)
		{
			TTXEng_SetInitLang(0xFF);//for exit TTXEng
			api_ttx_show_onoff(FALSE);			
		}
#endif
#if (CC_ON == 1 )
		if(pre_mode == OSD_SUBTITLE )
		{
			if(TRUE==api_get_atsccc_onoff())	//vicky20110216
				api_atsccc_show_onoff(FALSE);		
			#ifdef CC_BY_VBI
				cc_vbi_show_on(FALSE);
                        #endif
		}
#endif

#if (ISDBT_CC == 1)
        if(pre_mode == OSD_SUBTITLE )
        {
            api_isdbtcc_show_onoff(FALSE);
		}
#endif
		vpo_ioctl(g_vpo_dev, VPO_IO_GET_OUT_MODE, (UINT32)(&tvsys));

#if (COLOR_N==4)
		tOpenPara.eMode = OSD_4_COLOR;
#elif (COLOR_N==16)
		tOpenPara.eMode = OSD_16_COLOR;
#elif (COLOR_N==256)
		tOpenPara.eMode = OSD_256_COLOR;
#endif
		tOpenPara.uGAlphaEnable = 0;
		tOpenPara.uGAlpha = 0x0f;

		tOpenRect.uLeft = (720 - OSD_MAX_WIDTH)>>1;
		tOpenRect.uWidth = OSD_MAX_WIDTH;
		tOpenRect.uTop = OSD_STARTROW_P;
		tOpenRect.uHeight = OSD_MAX_HEIGHT;

		r.uLeft = 0;
		r.uTop = 0;
		r.uWidth = OSD_MAX_WIDTH;
		r.uHeight = OSD_MAX_HEIGHT;

		osd_dev = g_osd_dev2;
		OSDDrv_ShowOnOff((HANDLE)osd_dev,OSDDRV_OFF);
		OSDDrv_Close((HANDLE)osd_dev);
		OSDDrv_Open((HANDLE)osd_dev, &tOpenPara);
		osal_task_sleep(20);
		OSDDrv_CreateRegion((HANDLE)osd_dev, 0, &(tOpenRect), NULL);
		OSDDrv_RegionFill((HANDLE)osd_dev,0,&r, OSD_TRANSPARENT_COLOR);

        set_osd2_pos_for_tv_system(tvsys);

		/*Set pallette,for the second layer osd,it no need transparent*/
		pal_data = (UINT8*)OSD_GetRscPallette(0x4080 | system_config.osd_set.pallete);
		OSDDrv_SetPallette((HANDLE)osd_dev, pal_data, COLOR_N, OSDDRV_YCBCR);
		//OSDDrv_ShowOnOff((HANDLE)osd_dev,OSDDRV_ON);
		g_second_osd_mode = OSD_MSG_POPUP;
	}
	else if(mode == OSD_NO_SHOW)
	{
#if (CC_ON == 1 )
		if(	(pre_mode==OSD_SUBTITLE)	&&	(TRUE==api_get_atsccc_onoff())	)
		{
			api_atsccc_show_onoff(FALSE);		
			
		}	
		#ifdef CC_BY_VBI
			if(pre_mode==OSD_SUBTITLE)
				cc_vbi_show_on(FALSE);
		#endif
#endif		
#if (SUBTITLE_ON == 1) 
		if(TRUE == api_get_subt_onoff() && pre_mode == OSD_SUBTITLE && current_sub_mode == 0)
		{
			api_subt_show_onoff(FALSE);
		}
		else if((TRUE == api_get_subt_onoff()
#if (TTX_ON == 1)           
                 || TRUE == api_get_ttx_onoff()
#endif                 
                 )
                && (pre_mode == OSD_SUBTITLE && current_sub_mode == 1) || pre_mode == OSD_TELETEXT)
		{
		   //modify for TTX and EPG share buffer 2011 10 10
			#ifdef TTX_EPG_SHARE_MEM
            if((pre_mode == OSD_SUBTITLE)&&(TRUE == api_get_ttx_onoff()) )
                api_ttx_epg_share_epg_on();
            #endif
			//modify end
			TTXEng_SetInitLang(0xFF);//for exit TTXEng
#if (TTX_ON == 1)			
			api_ttx_show_onoff(FALSE);
#endif
			
		}
		else if(TRUE == api_get_subt_onoff() && pre_mode == OSD_MSG_POPUP)
		{
			OSDDrv_ShowOnOff((HANDLE)g_osd_dev2,OSDDRV_OFF);
		}
#endif		
#if (ISDBT_CC == 1)
        if(TRUE == api_get_isdbtcc_onoff()&& pre_mode == OSD_SUBTITLE )
        {
            api_isdbtcc_show_onoff(FALSE);
        }
        else if(TRUE == isdbtcc_is_available() && pre_mode == OSD_MSG_POPUP)
        {
            OSDDrv_ShowOnOff((HANDLE)g_osd_dev2,OSDDRV_OFF);
        }
#endif

        
		g_second_osd_mode = OSD_NO_SHOW;
	}
	else if(mode == OSD_SUBTITLE)
	{
		#if(CC_ON==1) //vicky20110216
		#ifdef CC_BY_OSD
		if(sys_data->osd_set.cc_display==1)
		{
			//if(get_dtv_cs_number()||get_cc_control_byte())
				api_atsccc_show_onoff(TRUE);
		}
		else
		{
			if(TRUE==api_get_atsccc_onoff())	//vicky20110216
				api_atsccc_show_onoff(FALSE); 
		}
		#endif
		#ifdef CC_BY_VBI			
			cc_vbi_show_on(TRUE);
		#endif
		
		#endif
		if(sys_data->osd_set.subtitle_display == 1)
		{
			//struct t_ttx_lang *ttxlang_list;
			UINT8 lang_numttx,sub_mode;

			sub_mode = 0;

#if (TTX_ON ==1)			
    			if((sel_lang == 0xFF)||(1==b_ttx_lang))
			{	
				sub_mode = 1;
				TTXEng_GetSubtLang(&ttxlang_list, &lang_num);
				sel_lang = api_ttxsub_getlang(ttxlang_list,NULL,sys_data->lang.sub_lang,lang_num);				
			}
#endif

#if (SUBTITLE_ON == 1) 
			if(sys_data->osd_set.subtitle_lang != SUBTITLE_LANGUAGE_INVALID)
			{
				subt_get_language(&sublang_list,&lang_num);
				TTXEng_GetSubtLang(&ttxlang_list, &lang_numttx);
				
				if(((lang_num + lang_numttx) > 0) && (sys_data->osd_set.subtitle_lang < (lang_num + lang_numttx)))
				{
					if(lang_numttx>0 && sys_data->osd_set.subtitle_lang <lang_numttx)
					{
						sub_mode = 1;/*ttx-subtitle*/
						sel_lang = sys_data->osd_set.subtitle_lang;
					}
					else if((lang_num>0) && (sys_data->osd_set.subtitle_lang <(lang_num + lang_numttx)))
					{
						sub_mode = 0;/*normal-subtitle*/
						sel_lang = (sys_data->osd_set.subtitle_lang - lang_numttx);
					}
				}
				else
				{		
					PRINTF("NO SUBTITLE DATA.\n");
				}
					
			}
			
			if(sel_lang != 0XFF)/*subt languages exist*/
			{
				if(sub_mode == 0)
				{
#if (CC_ON ==1)
	#ifdef CC_BY_OSD
		api_atsccc_show_onoff(FALSE);	//vicky20110216
        #endif
#endif				
#if (TTX_ON ==1)
					api_ttx_show_onoff(FALSE);
#endif

#if (SUBTITLE_ON == 1)
                 if(TRUE == subt_is_available())
                 {
					api_subt_show_onoff(TRUE);
					subt_set_language(sel_lang);
					#if defined(_VMX_CA_ENABLE_)
					update_subt_pid(lang_num);
					#endif
                 }
#endif				
				}
				else
				{
#if (CC_ON ==1)
	#ifdef CC_BY_OSD
		api_atsccc_show_onoff(FALSE);	//vicky20110216
        #endif
#endif				
#if (SUBTITLE_ON == 1 )
					api_subt_show_onoff(FALSE);
#endif

#if (TTX_ON ==1)
//modify for TTX and EPG share buffer 2011 10 10
#ifdef TTX_EPG_SHARE_MEM
					epg_off();
                    epg_reset();
					epg_release();
				        ttx_enable(TRUE);
#endif//modify end
					api_ttx_show_onoff(TRUE);
					TTXEng_SetSubtLang(sel_lang);
#endif
				}
			}
#endif

#if (ISDBT_CC == 1)
		//libc_printf("\nOsd mode change and lang num(%d)",bLangNum);
	if(TRUE == isdbtcc_is_available()||FALSE ==subt_is_available())
	{
		api_isdbtcc_show_onoff(TRUE);
		if(	(SUBTITLE_LANGUAGE_INVALID==bCcLang)  || (0>=bLangNum) || (bLangNum<=bCcLang))
		{
			//api_isdbtcc_show_onoff(FALSE);
		}
		else
		{			
			isdbtcc_set_language(bCcLang);				
		}
	}
#endif	            
			
			current_sub_mode = sub_mode;
		}
		else
		{
			/*Even subt off,we should still close ttx*/	
#if (TTX_ON ==1)
				api_ttx_show_onoff(FALSE);
#endif
		}
		g_second_osd_mode = OSD_SUBTITLE;
	}
	else if(mode == OSD_TELETEXT)
	{
#if (TTX_ON ==1)
		PRINTF("TELETEXT\n");
#if (SUBTITLE_ON == 1 )
		api_subt_show_onoff(FALSE);

#endif
#if (CC_ON ==1)
	#ifdef CC_BY_OSD
		api_atsccc_show_onoff(FALSE);	//vicky20110216
        #endif
#endif	
		api_ttx_show_onoff(TRUE);
		g_second_osd_mode = OSD_TELETEXT;
#endif
	}
	else if(mode == OSD_INVALID_MODE)
		g_second_osd_mode = OSD_INVALID_MODE;		

	#if defined(SUPPORT_VMX_STD) || defined(SUPPORT_VMX)	//vicky130304
	osal_semaphore_release(vmx_osd_sema_id);
	return mode;
	#endif
	return pre_mode;
}
#endif

/*	num:    bit14~bit0  longitude/latitude
	bit15  0  east/north
	1  west/south
	return:  -180 ~ 180 / -90 ~ 90   longitude/latitude*/
double api_usals_local_word2double(UINT16 num)
{
	double result;
	
	result = num&0x7fff;
	
	if(num&0x8000)
		result *= -1;
	
	result /= 100.0;   		//current longitude

	return result;
}

BOOL api_check_usals_angle( UINT16 sat_pos)
{
	double sat_orbit;
	double local_longitude, local_latitude;
	S_NODE s_node;
	SYSTEM_DATA *sys = sys_data_get();

	get_sat_at(sat_pos , VIEW_ALL, &s_node);
	
	sat_orbit = api_usals_get_sat_orbit(s_node.sat_orbit);
	local_longitude = api_usals_local_word2double(sys->local.local_longitude);

	local_latitude = api_usals_local_word2double(sys->local.local_latitude);

	/*Usals_Target_Formula_Calcuate*/

	if(api_usals_target_formula_calcuate(sat_orbit, local_longitude,local_latitude) > 90.0)
		return TRUE;
	else
		return FALSE;

}


/**************************************************************
	id:  logo  id 
	addr: return address
	len: retrun data length
	return : false , true 
	
****************************************************************/
//#ifdef LOGO_SUPPORT
UINT8 api_get_chunk_add_len(UINT32 id,UINT32* addr,UINT32* len)
{
	INT32 ret;
	CHUNK_HEADER chuck_hdr;

	ret = sto_get_chunk_header(id,&chuck_hdr);
	if(ret==0)
		return 0;

	*addr = (UINT32)sto_chunk_goto(&id,0xFFFFFFFF,1) + CHUNK_HEADER_SIZE;
	*len = chuck_hdr.len - CHUNK_HEADER_SIZE + CHUNK_NAME;

	return 1;
}


void api_show_bootup_logo(void)
{
    	int i;    
	void* pWriteBuffer;
    	UINT32 uSizeGot;
	RET_CODE ret_code;
    	UINT32 logo_id,addr,len;   
	struct sto_device *sto_flash_dev;
#ifdef DUAL_ENABLE
    UINT8 *logo_buf;
#endif

    logo_id = BOOT_LOGO_ID;
    if(api_get_chunk_add_len(logo_id,&addr,&len) ==0 )
        return;
#ifdef DUAL_ENABLE    
     logo_buf = (UINT8 *)MALLOC(len);
#endif
    //screen_back_state = SCREEN_BACK_MENU;
        
    	ret_code = vdec_start((struct vdec_device *)dev_get_by_id(HLD_DEV_TYPE_DECV, 0));
	sto_flash_dev = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0);

	for(i=0;i<2;i++)
	{
		ret_code = vdec_vbv_request(g_decv_dev,len,	&pWriteBuffer,&uSizeGot,NULL);
#ifdef DUAL_ENABLE            
    	sto_get_data(sto_flash_dev, (UINT8 *)logo_buf, addr, uSizeGot);
        MEMCPY(pWriteBuffer,logo_buf,uSizeGot);
#else
		sto_get_data(sto_flash_dev, (UINT8 *)pWriteBuffer, addr, uSizeGot);
#endif
		vdec_vbv_update(g_decv_dev, uSizeGot);
	}
#ifdef DUAL_ENABLE    
    FREE(logo_buf);
#endif
}

#ifndef NEW_DEMO_FRAME
void api_video_set_pause(UINT8 flag)
{
    if(flag)
        UIChChgPauseProg();
    else
        UIChChgResumeProg();
}

void api_show_radio_logo(void)
{
	UINT32 addr, len;		
	api_set_vpo_dit(TRUE);
	if(api_get_chunk_add_len(RADIO_LOGO_ID, &addr, &len))
		UIChChgShowLogo((UINT8*)addr, len, TRUE);
}

#ifdef USB_MP_SUPPORT
void api_show_mediaplay_logo(void)
{
	UINT32 addr, len;		
	api_set_vpo_dit(TRUE);
	if(api_get_chunk_add_len(MEDIA_LOGO_ID, &addr, &len))
		UIChChgShowLogo((UINT8*)addr, len, TRUE);
}
#endif

void api_show_menu_logo(void)
{
	UINT32 addr, len;		
#if (SUBTITLE_ON == 1) 
    api_subt_show_onoff(FALSE);
#endif
#if (CC_ON ==1)
    api_atsccc_show_onoff(FALSE);	//vicky20110124
#endif
#if (ISDBT_CC == 1)
	api_isdbtcc_show_onoff(FALSE);
#endif
    api_set_vpo_dit(TRUE);
	if(api_get_chunk_add_len(MENU_LOGO_ID, &addr, &len))
		UIChChgShowLogo((UINT8*)addr, len, TRUE);
}
#else
void api_video_set_pause(UINT8 flag)
{
	struct vdec_device *vdec = is_cur_decoder_avc() ? dev_get_by_name("DECV_AVC_0") : dev_get_by_id(HLD_DEV_TYPE_DECV, 0);

    	if ( flag )
		chchg_pause_video(vdec);
	else
		chchg_resume_video(vdec);
}

void api_show_radio_logo(void)
{
	UINT32 addr, len;	
	struct cc_logo_info logo;
	struct cc_device_list dev_list;

#ifndef _BUILD_OTA_E_
	if(api_get_chunk_add_len(RADIO_LOGO_ID, &addr, &len))
	{
		MEMSET(&logo, 0, sizeof(logo));
		logo.addr = (UINT8 *)addr;
		logo.size = len;
		logo.sto = dev_get_by_id(HLD_DEV_TYPE_STO, 0);
		MEMSET(&dev_list, 0, sizeof(struct cc_device_list));
		dev_list.vpo = dev_get_by_id(HLD_DEV_TYPE_DIS, 0);
		dev_list.vdec = dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
		dev_list.vdec_hdtv = g_decv_avc_dev;
		dev_list.vdec_stop = (is_cur_decoder_avc() == TRUE) ? g_decv_avc_dev : dev_list.vdec;
		dev_list.deca = dev_get_by_id(HLD_DEV_TYPE_DECA, 0);
		dev_list.snd_dev = dev_get_by_id(HLD_DEV_TYPE_SND, 0);
		dev_list.dmx = dev_get_by_id(HLD_DEV_TYPE_DMX, ap_get_main_dmx());
		chchg_show_logo(&logo, &dev_list);		
	}
#endif
}

#ifdef USB_MP_SUPPORT
void api_show_mediaplay_logo(void)
{
	UINT32 addr, len;	
	struct cc_logo_info logo;
	struct cc_device_list dev_list;

#ifndef _BUILD_OTA_E_
	if(api_get_chunk_add_len(MEDIA_LOGO_ID, &addr, &len))
	{
		MEMSET(&logo, 0, sizeof(logo));
		logo.addr = (UINT8 *)addr;
		logo.size = len;
		logo.sto = dev_get_by_id(HLD_DEV_TYPE_STO, 0);
		MEMSET(&dev_list, 0, sizeof(struct cc_device_list));
		dev_list.vpo = dev_get_by_id(HLD_DEV_TYPE_DIS, 0);
		dev_list.vdec = dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
		dev_list.vdec_hdtv = g_decv_avc_dev;
		dev_list.vdec_stop = (is_cur_decoder_avc() == TRUE) ? g_decv_avc_dev : dev_list.vdec;
		dev_list.deca = dev_get_by_id(HLD_DEV_TYPE_DECA, 0);
		dev_list.snd_dev = dev_get_by_id(HLD_DEV_TYPE_SND, 0);
		dev_list.dmx = dev_get_by_id(HLD_DEV_TYPE_DMX, ap_get_main_dmx());
		chchg_show_logo(&logo, &dev_list);	
	}
#endif
}
#endif

extern void api_show_row_logo(UINT32 logo_id);

void api_show_menu_logo(void)
{
	UINT32 addr, len;
	struct cc_logo_info logo;
	struct cc_device_list dev_list;

	//api_show_row_logo(MENU_LOGO_ID);
	//return;
#ifndef _BUILD_OTA_E_
	if(api_get_chunk_add_len(MENU_LOGO_ID, &addr, &len))
	{
		MEMSET(&logo, 0, sizeof(logo));
		logo.addr = (UINT8 *)addr;
		logo.size = len;
		logo.sto = dev_get_by_id(HLD_DEV_TYPE_STO, 0);
		MEMSET(&dev_list, 0, sizeof(struct cc_device_list));
		dev_list.vpo = dev_get_by_id(HLD_DEV_TYPE_DIS, 0);
		dev_list.vdec = dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
		dev_list.vdec_hdtv = g_decv_avc_dev;
		dev_list.vdec_stop = (is_cur_decoder_avc() == TRUE) ? g_decv_avc_dev : dev_list.vdec;
		dev_list.deca = dev_get_by_id(HLD_DEV_TYPE_DECA, 0);
		dev_list.snd_dev = dev_get_by_id(HLD_DEV_TYPE_SND, 0);
		dev_list.dmx = dev_get_by_id(HLD_DEV_TYPE_DMX, ap_get_main_dmx());
		chchg_show_logo(&logo, &dev_list);
	}
#endif
}

#endif
static BOOL is_vdec_first_shown_other = FALSE;
/* First Video Frame Already Show */
static void cb_vdec_first_show_other(UINT32 uParam1, UINT32 uParam2)
{
	is_vdec_first_shown_other = TRUE;
}

/* Check whether First Vedio Frame Already Show or not */
static BOOL ck_vdec_first_show_other(void)
{
	return is_vdec_first_shown_other;
}

/* Reset First Vedio Frame not Show */
static void reset_vdec_first_show_other(void)
{
	is_vdec_first_shown_other = FALSE;
}
void api_show_row_logo(UINT32 logo_id)
{
	int i;    
	void* pWriteBuffer;
	UINT32 uSizeGot;
	RET_CODE ret_code;
	UINT32 addr,len;
	struct VDec_StatusInfo CurStatus;
#ifdef DUAL_ENABLE
	UINT8 *logo_buf;
#endif
	struct sto_device* sto_flash_dev = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0);

	CHUNK_HEADER chuck_hdr;
	if(sto_get_chunk_header(logo_id, &chuck_hdr) == 0)
		return;

	addr = (UINT32)sto_chunk_goto(&logo_id, 0xFFFFFFFF, 1) + CHUNK_HEADER_SIZE;
	len = chuck_hdr.len - CHUNK_HEADER_SIZE + CHUNK_NAME;

#ifdef DUAL_ENABLE
	logo_buf = (UINT8 *)MALLOC(len);
#endif

	ret_code = vdec_stop(g_decv_dev,FALSE,FALSE);
	struct vdec_io_reg_callback_para tpara;
	reset_vdec_first_show_other();
	tpara.eCBType = VDEC_CB_FIRST_SHOWED;
	tpara.pCB = cb_vdec_first_show_other;
	vdec_io_control(g_decv_dev, VDEC_IO_REG_CALLBACK, (UINT32)(&tpara));
#ifdef DUAL_ENABLE
	vdec_io_control(g_decv_dev, VDEC_SET_DMA_CHANNEL, (UINT32)DMA_INVALID_CHA);	
#endif
	ret_code = vdec_start(g_decv_dev);
	for(i=0; i<2; i++)
	{
		ret_code = vdec_vbv_request(g_decv_dev, len, &pWriteBuffer,&uSizeGot,NULL);
#ifdef DUAL_ENABLE
		sto_get_data(sto_flash_dev, (UINT8 *)logo_buf, addr, uSizeGot);
		MEMCPY(pWriteBuffer,logo_buf,uSizeGot);
#else
		sto_get_data(sto_flash_dev, (UINT8 *)pWriteBuffer, addr, uSizeGot);
#endif
		vdec_vbv_update(g_decv_dev, uSizeGot);
	} 
#if 0
    MEMSET(&CurStatus,0,sizeof(struct VDec_StatusInfo));
    for(i=0;i<100;i++) //waiting
     {
        osal_task_sleep(3);
	    vdec_io_control(g_decv_dev, VDEC_IO_GET_STATUS, (UINT32)&CurStatus);
        if(CurStatus.uFirstPicShowed)
        
		break;
    }
	if(CurStatus.uFirstPicShowed == 0)
	{
		libc_printf("show logo error!\n");
	}
#endif
	//adopt the new method to ensure de_o getting frame under dual_output mode
	UINT32 count = 0;
	osal_task_sleep(10);
	while(1)
	{
		vdec_io_control(g_decv_dev, VDEC_IO_GET_STATUS, (UINT32)&CurStatus);
		if(!CurStatus.uFirstPicShowed)
		{
			osal_task_sleep(10);
			if(++count > 400)
			{
				libc_printf("show log failed\n");
				//SDBBP();
				break;
			}
		}
		else
			break;
	}
	
	ret_code = vdec_stop(g_decv_dev,FALSE,FALSE);
#ifdef DUAL_ENABLE
    FREE(logo_buf);
#endif		
	return;
}

int api_parse_defaultset_subblock(void)
{
	unsigned chid;
	int i,sub_cnt;
	unsigned char sb_type;
	unsigned long addr,end_addr;
	SUBBLOCK_HEADER hd;
   	struct sto_device *sto;

	unsigned char item_type,byte,byte2;
	unsigned long item_datalen,n;	
	SYSTEM_DATA* sys_data;

	sto = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0);
	if(sto == NULL)
		return 0;
	sys_data = sys_data_get();
  

	chid = 0x03FC0100;
	sb_type = 0x02;
	
	sub_cnt = sto_subblock_count(chid);
	if(sub_cnt==0)
		return 0;
	
	addr = sto_subblock_goto(chid, &sb_type,0xFF,1);
	if(addr & 0x80000000) 
		return 0;		
	sto_get_subblock_header(0x03FC0100,sb_type,&hd);
	addr += SUBBLOCK_HEADER_SIZE;

	end_addr = addr + hd.len;
	while(addr<end_addr)
	{
		sto_get_data(sto, &item_type, addr++, 1);
		if(item_type == 0x00 || item_type == 0xFF)
			break;

		n = 0;
		item_datalen = 0;
		while(n++<4)
		{
			item_datalen <<= 7;
			sto_get_data(sto, &byte, addr++, 1);
			item_datalen += byte & 0x7F;
			if ((byte & 0x80) == 0x00)	/* length field byte end. */
				break;
		}

		if(byte & 0x80)	break;	/* item data length field error (>4Bs) */

		switch(item_type)
		{
		case 0x01:	/* Fav group name */
#ifdef FAV_GROP_RENAME	
			{
				unsigned char favgrp_cnt,favgrp_namelen,favgrp_code;
				sto_get_data(sto, &favgrp_cnt,		addr + 0, 1);
				sto_get_data(sto, &favgrp_namelen,	addr + 1, 1);
				sto_get_data(sto, &favgrp_code,	addr + 2, 1);
				if(favgrp_cnt > MAX_FAVGROUP_NUM)
					favgrp_cnt = MAX_FAVGROUP_NUM;
				if(favgrp_cnt == 0xFF || favgrp_namelen == 0xFF || favgrp_code == 0xFF)
					break;
				if(favgrp_code != 0x00 && favgrp_code != 0x01)
					break;
				
				byte 	= favgrp_namelen;
				if(byte>FAV_GRP_NAME_LEN)
					byte = FAV_GRP_NAME_LEN;
				
				for(i=0;i<favgrp_cnt;i++)
				{
					sto_get_data(sto, sys_data->favgrp_names[i],	addr + 3 + favgrp_namelen*i, byte);
					
					if(favgrp_code == 0)
					{
                        if(favgrp_namelen > FAV_GRP_NAME_LEN)
                            sys_data->favgrp_names[i][FAV_GRP_NAME_LEN] = '\0';
                        else
						    sys_data->favgrp_names[i][favgrp_namelen] = '\0';
					}
				}
			}
#endif
			break;
		default:
			;
		}			

		addr += item_datalen;		
	}	
	
}

BOOL	api_tv_radio_switch()
{
	UINT16	channel;
	UINT8	uAVMode;
	uAVMode = sys_data_get_cur_chan_mode();

	//1Switch TV to Audio
	if(PROG_TV_MODE == uAVMode)
	{
		sys_data_set_cur_chan_mode(PROG_RADIO_MODE);
	}
	else
	{
		sys_data_set_cur_chan_mode(PROG_TV_MODE);
	}

	//channel = get_node_num(TYPE_PROG_NODE, NULL);
	channel = get_prog_num(VIEW_ALL | uAVMode, 0);

	//no program
	if(0 == channel)
	{
		//popup no program message
		sys_data_set_cur_chan_mode(uAVMode);
		return FALSE;
	}
	else
	{
		if(PROG_TV_MODE == uAVMode)
			api_show_radio_logo();
		sys_data_change_group(sys_data_get_cur_group_index());
		return TRUE;
	}	
}

/**************************************************************
	check leap year 
****************************************************************/
UINT8 api_check_is_leap_year(UINT16 yy)
{
	if(  (yy%4==0 && yy%100!=0) || yy%400==0)
	    return 1;
	else
	    return 0;
}

/*******************************************************
    yy,mm,dd,valid --(I/O) Input year,month,day time to check is valid
    type           --(I/O) check day valid, 
                    (when daily,weekly type = 0,
                        else if monthly type  = 1
                        else if yearly type = 2)
***************************************************************/

static UINT8 month_days[12] =
{
	/*1  2  3 4  5  6   7  8  9 10 11 12  */
	31,28,31,30,31,30,  31,31,30,31,30,31
};

/*
return:
 0  	-- OK
 -1 	-- year < 2000 || year>2100)
 -2     -- month==0 || month>12
 -3     -- day==0 || day>max days of this month
*/
INT32 api_check_valid_date(UINT16 year,UINT8 month, UINT8 day)
{
	UINT8  mm_days;

	mm_days = month_days[month-1];
	if(month==2 && api_check_is_leap_year(year))
		mm_days = 29;
	if(year<2000 || year>2100)
		return -1;
	if(month == 0 || month>12)
		return -2;
	if(day==0 || day>mm_days)
		return -3;

	return 0;
}

BOOL api_correct_yy_mm_dd(UINT16* yy,UINT8* mm,UINT8* dd,UINT8 type)
{
	UINT16 year;
	UINT8  month,day,mm_days;
	BOOL b;
	year    = *yy;
	month   = *mm;
	day     = *dd;

	INIT_DATETIME_CHECK:
		if(day <= 0)  // hong zhang 050430
		{
			month -= 1;
		}
	
	/* For monthly */
	if(month>12)
	{
	    year += 1;
	    month = 1;
	}
	else if(month <= 0)   // hong zhang 050430
	{
		year -= 1;
		month = 12;
	}

	mm_days = month_days[month-1];
	if(month==2 && api_check_is_leap_year(year))
	mm_days = 29;

	if(type==0)//daily,weekly
	{
		if(day>mm_days)
		{
			day -= mm_days;
			month += 1;
			if(month>12)
			{
				month = 1;
				year += 1;
			}                
		}
		else if(day <= 0)  // hong zhang 050430
		{
			day = mm_days;
		}

		b = TRUE;        
	}
	else//monthly or yearly
	{

		if(day<=mm_days)
		{
			b = TRUE;
		}
		else if(type==1)//monthly
		{
			month += 1;
			goto INIT_DATETIME_CHECK;
		}
		else if(type==2)//yearly
		{
			year += 1;
			goto INIT_DATETIME_CHECK;
		}        
	}

	*yy = year;
	*mm = month;
	*dd = day;

	b = TRUE;

	return TRUE;
    
}

/*************************************
return:
	0	- dt1 = dt2
	1   	- dt1 > dt2
	-1  	- dt1 < dt2
**************************************/
INT32 api_compare_time(date_time *dt1, date_time *dt2)
{
	if (dt1->hour > dt2->hour)
		return 1;
	else if (dt1->hour < dt2->hour)
		return -1;
	
	if (dt1->min > dt2->min)
		return 1;
	else if (dt1->min < dt2->min)
		return -1;
	
	return 0;
}

INT32 api_compare_time_ext(date_time *dt1, date_time *dt2)
{
	if (dt1->hour > dt2->hour)
		return 1;
	else if (dt1->hour < dt2->hour)
		return -1;
	
	if (dt1->min > dt2->min)
		return 1;
	else if (dt1->min < dt2->min)
		return -1;

	if (dt1->sec > dt2->sec)
		return 1;
	else if (dt1->sec < dt2->sec)
		return -1;

	
	return 0;
}


INT32 api_compare_day(date_time *dt1, date_time *dt2)
{
	if(dt1->year > dt2->year)
		return 1;
	else if(dt1->year < dt2->year)
		return -1;

	if(dt1->month > dt2->month)
		return 1;
	else if(dt1->month < dt2->month)
		return -1;

	if(dt1->day > dt2->day)
		return 1;
	else if(dt1->day < dt2->day)
		return -1;
	
	return 0;
}

INT32 api_compare_day_time(date_time *dt1, date_time *dt2)
{
	INT32 nRet = api_compare_day(dt1, dt2);
	if (nRet != 0) return nRet;
	return api_compare_time(dt1, dt2);
}


INT32 api_compare_day_time_ext(date_time *dt1, date_time *dt2)
{
	INT32 nRet = api_compare_day(dt1, dt2);
	if (nRet != 0) return nRet;
	return api_compare_time_ext(dt1, dt2);
}


BOOL set_next_wakeup_datetime(TIMER_SET_CONTENT* timer)
{
	UINT16  next_yy;
	UINT8   next_mm,next_dd;
	UINT8   type;
	next_yy = timer->wakeup_year;
	next_mm = timer->wakeup_month;
	next_dd = timer->wakeup_day;

	type = 0xFF;

	if(timer->timer_mode == TIMER_MODE_ONCE)
	{
		timer->timer_mode = TIMER_MODE_OFF;
	}
	else if(timer->timer_mode == TIMER_MODE_DAILY)
	{
		next_dd += 1;                    
		type = 0;
	}
	else if(timer->timer_mode == TIMER_MODE_WEEKLY)
	{
		next_dd += 7;
		type = 0;
	}
	else if(timer->timer_mode == TIMER_MODE_MONTHLY)
	{
		next_mm += 1;
		type = 1;
	}
	else if(timer->timer_mode == TIMER_MODE_YEARLY)
	{
		next_yy += 1;
		type = 2;
	}

	if(type != 0xFF)
	{
		api_correct_yy_mm_dd(&next_yy,&next_mm,&next_dd,type);
		timer->wakeup_year = next_yy;
		timer->wakeup_month= next_mm;
		timer->wakeup_day  = next_dd;

		return TRUE;
	}
	else
		return FALSE;

}


void update_yy_mm_dd(UINT16* yy,UINT8* mm,UINT8* dd,UINT8 type)
{
	date_time	dt;
    
    UINT16 year,cur_year;
    UINT8  month,day,mm_days,cur_month,cur_day;
    BOOL b;

    
	get_local_time(&dt);

    cur_year    = dt.year;
    cur_month   = dt.month;
    cur_day     = dt.day;

    year    = *yy;
    month   = *mm;
    day     = *dd;

    while( (year < cur_year)
        || (year == cur_year && month < cur_month)
        || (year == cur_year && month == cur_month && day<cur_day) 
        )
    {

        if(type == TIMER_MODE_DAILY)
            day += 1;
        else if(type == TIMER_MODE_WEEKLY)
            day += 7;
        else if(type == TIMER_MODE_MONTHLY)
            month += 1;
        else//TIMER_MODE_YEARLY
            year += 1;

        
        /* For monthly */
        if(month>12)
        {
            year += 1;
            month = 1;
        }
        
        mm_days = month_days[month-1];
        if(month==2 && api_check_is_leap_year(year))
            mm_days = 29;

        if(day>mm_days)
        {
            day -= mm_days;
            month += 1;
            if(month>12)
            {
                month = 1;
                year += 1;
            }                
        }
    }
    
    *yy = year;
    *mm = month;
    *dd = day;
    
}

/*****************************************
function: api_compare_timer
parameter:
	timer1:[a,b], wakeup time on a, and duration time is (b-a)
	timer2:[c,d], wakeup time on c, and duration time is (c-d)
return:
	0 	- [a,b]=[c,d]
	1 	- [a,b] ^[c,d] = NULL, b<c
	2	- [a,b] ^[c,d] = NULL, d<a
	-1 	- other
******************************************/
INT32 api_compare_timer(TIMER_SET_CONTENT* timer1,TIMER_SET_CONTENT* timer2)
{
	date_time time_a,time_b,time_c,time_d;

	MEMSET(&time_a, 0, sizeof(date_time));
	MEMSET(&time_b, 0, sizeof(date_time));
	MEMSET(&time_c, 0, sizeof(date_time));
	MEMSET(&time_d, 0, sizeof(date_time));

	time_a.year = time_b.year = timer1->wakeup_year;
	time_a.month = time_b.month = timer1->wakeup_month;
	time_a.day = time_b.day = timer1->wakeup_day;
	time_a.hour = timer1->wakeup_time/60;
	time_a.min = timer1->wakeup_time%60;

	time_b.hour = (timer1->wakeup_time+ timer1->wakeup_duration_time)/60;
	time_b.min = (timer1->wakeup_time+ timer1->wakeup_duration_time)%60;

	if(time_b.hour > 23)
	{
		time_b.hour %= 24;
		time_b.day++;
		api_correct_yy_mm_dd(&time_b.year,&time_b.month,&time_b.day,0);
	}
	
	time_c.year = time_d.year = timer2->wakeup_year;
	time_c.month = time_d.month = timer2->wakeup_month;
	time_c.day = time_d.day = timer2->wakeup_day;
	time_c.hour = timer2->wakeup_time/60;
	time_c.min = timer2->wakeup_time%60;

	time_d.hour = (timer2->wakeup_time+ timer2->wakeup_duration_time)/60;
	time_d.min = (timer2->wakeup_time+ timer2->wakeup_duration_time)%60;

	if(time_d.hour > 23)
	{
		time_d.hour %= 24;
		time_d.day++;
		api_correct_yy_mm_dd(&time_d.year,&time_d.month,&time_d.day,0);
	}

	if(api_compare_day_time(&time_a,&time_c)==0 && api_compare_day_time(&time_b,&time_d)==0)
		return 0;

	if(api_compare_day_time(&time_b,&time_c)<=0)
		return 1;

	 if(api_compare_day_time(&time_a,&time_d)>=0 )
	 	return 2;

	return -1;
}

/*****************************************
function: api_compare_timer_time
parameter:
	timer1:[a,b], wakeup time on a, and duration time is (b-a)
	timer2:[c,d], wakeup time on c, and duration time is (c-d)
return:
	0 	- [a,b]=[c,d]
	1 	- [a,b] ^[c,d] = NULL, b<c
	2	- [a,b] ^[c,d] = NULL, d<a
	-1 	- other
******************************************/
INT32 api_compare_timer_time(TIMER_SET_CONTENT* timer1,TIMER_SET_CONTENT* timer2)
{
	date_time time_a,time_b,time_c,time_d;

	MEMSET(&time_a, 0, sizeof(date_time));
	MEMSET(&time_b, 0, sizeof(date_time));
	MEMSET(&time_c, 0, sizeof(date_time));
	MEMSET(&time_d, 0, sizeof(date_time));

	time_a.hour = timer1->wakeup_time/60;
	time_a.min = timer1->wakeup_time%60;

	time_b.hour = (timer1->wakeup_time+ timer1->wakeup_duration_time)/60;
	time_b.min = (timer1->wakeup_time+ timer1->wakeup_duration_time)%60;

	if(time_b.hour > 23)
	{
		time_b.hour %= 24;
		time_b.day++;
	}
	
	time_c.hour = timer2->wakeup_time/60;
	time_c.min = timer2->wakeup_time%60;

	time_d.hour = (timer2->wakeup_time+ timer2->wakeup_duration_time)/60;
	time_d.min = (timer2->wakeup_time+ timer2->wakeup_duration_time)%60;

	if(time_d.hour > 23)
	{
		time_d.hour %= 24;
		time_d.day++;
	}

	if(api_compare_day_time(&time_a,&time_c)==0 && api_compare_day_time(&time_b,&time_d)==0)
		return 0;

	if(api_compare_day_time(&time_b,&time_c)<=0)
		return 1;

	 if(api_compare_day_time(&time_a,&time_d)>=0 )
	 	return 2;

	return -1;
}

/*****************************************
function: api_check_timer
parameter:
	timer1:[a,b], wakeup time on a, and duration time is (b-a)
	timer2:[c,d], wakeup time on c, and duration time is (c-d)
return:
	0 	- [a,b] ^ [c,d] != NULL
	1 	- [a,b] ^ [c,d] = NULL
******************************************/
INT32 api_check_timer(TIMER_SET_CONTENT* timer1,TIMER_SET_CONTENT* timer2)
{
	TIMER_SET_CONTENT timer_1;
	INT32 ret;
	UINT8   next_mm,next_dd;
	UINT16  next_yy;
	UINT8   type;

	ret = api_compare_timer(timer1, timer2);

	if(ret <= 0) return 0;

	if(ret == 2) return 1;

	timer_1 = *timer1;
	next_yy = timer1->wakeup_year;
	next_mm = timer1->wakeup_month;
	next_dd = timer1->wakeup_day;
	type = 0xFF;
	 
	switch(timer1->timer_mode)
	{
		case TIMER_MODE_OFF:
		case TIMER_MODE_ONCE:
			return 1;
		case TIMER_MODE_DAILY:
COMPARE_TIME_DURATION:
			if(api_compare_timer_time(timer1, timer2)>0)
				return 1;
			else
				return 0;
		case TIMER_MODE_WEEKLY:
			next_dd += 7;                    
			type = 0;
			break;
		case TIMER_MODE_MONTHLY:
			if(timer2->timer_mode == TIMER_MODE_MONTHLY)
			{
				if(timer1->wakeup_day>=28 && timer2->wakeup_day>=28)
				{
					goto COMPARE_TIME_DURATION;
				}
			}
			else if(timer2->timer_mode == TIMER_MODE_YEARLY)
			{
				if(timer1->wakeup_day>28 
					&& timer2->wakeup_day>=28 
					&& timer2->wakeup_day<=timer1->wakeup_day)
				{
					goto COMPARE_TIME_DURATION;
				}
			}
			next_mm += 1;
			type = 1;
			break;
		case TIMER_MODE_YEARLY:
			if(timer2->timer_mode == TIMER_MODE_MONTHLY)
			{
				do
				{
					next_yy += 1;
					type = 2;
					api_correct_yy_mm_dd(&next_yy,&next_mm,&next_dd,type);
					timer_1.wakeup_year = next_yy;
					timer_1.wakeup_month= next_mm;
					timer_1.wakeup_day  = next_dd;
				}while(api_compare_timer(&timer_1, timer2)==1);
				
				return api_check_timer(timer2,&timer_1);
			}
			next_yy += 1;
			type = 2;
			break;
	}

	if(timer2->timer_mode == TIMER_MODE_DAILY)
	{
		goto COMPARE_TIME_DURATION;
	}
     
	if(type != 0xFF)
	{
		api_correct_yy_mm_dd(&next_yy,&next_mm,&next_dd,type);
		timer_1.wakeup_year = next_yy;
		timer_1.wakeup_month= next_mm;
		timer_1.wakeup_day  = next_dd;
	}
	
	return api_check_timer(&timer_1,timer2);
}

BOOL api_timers_running(void)
{
	UINT16 i;
	SYSTEM_DATA *sys_data;
	TIMER_SET_T* timer_set;
	TIMER_SET_CONTENT* timer;
	
	sys_data = sys_data_get();
	timer_set = &(sys_data->timer_set);
	for(i=0;i<MAX_TIMER_NUM;i++)
	{
		timer = &(timer_set->TimerContent[i]);
		if(timer->wakeup_state == TIMER_STATE_RUNING)
			return TRUE;
	}

	return FALSE;
}

UINT8 api_get_first_timer(void)
{
	UINT8 i,timer_idx;
	SYSTEM_DATA* sys_data;
	TIMER_SET_T* timer_set;
	TIMER_SET_CONTENT* timer;
	date_time	dt,firsttime,timertime;

	timer_idx = 0xff;
	firsttime.sec = 0;
	get_local_time(&dt);
	sys_data = sys_data_get();
	timer_set = &sys_data->timer_set;

	//    dt.sec = timertime.sec = 0; /* Ignore second*/
	for(i=0;i<MAX_TIMER_NUM;i++)
	{
        timer = &timer_set->TimerContent[i];
        
        if(timer->timer_mode == TIMER_MODE_OFF)
            continue;
        if(timer->timer_service != TIMER_SERVICE_CHANNEL 
            && timer->timer_service != TIMER_SERVICE_MESSAGE
#ifdef DVR_PVR_SUPPORT            
            && timer->timer_service != TIMER_SERVICE_DVR_RECORD
#endif            
            )
            continue;
        if(timer->wakeup_state == TIMER_STATE_RUNING)
        {
            if(timer->timer_mode == TIMER_MODE_ONCE)
            {
                timer->timer_mode = TIMER_MODE_OFF; 
                continue;
            }
            else
                set_next_wakeup_datetime(timer);
        }
        
        
        timertime.year = timer->wakeup_year;
        timertime.month = timer->wakeup_month;
        timertime.day = timer->wakeup_day;
        timertime.hour = timer->wakeup_time/60;
        timertime.min = timer->wakeup_time%60;            
        
        if(api_compare_day_time(&timertime,&dt) < 0)
        {
            set_next_wakeup_datetime(timer);
            
            timertime.year = timer->wakeup_year;
            timertime.month = timer->wakeup_month;
            timertime.day = timer->wakeup_day;
            timertime.hour = timer->wakeup_time/60;
            timertime.min = timer->wakeup_time%60;            
        }

        if(api_compare_day_time(&timertime,&dt) < 0) 
            continue;
            
        
        if(timer_idx == 0xff)
        {
            firsttime = timertime;
            timer_idx = i;
        }
        else
        {
            if(api_compare_day_time(&timertime,&firsttime) < 0)
            {
                firsttime = timertime;
                timer_idx = i;
            }
        }
        
    }

    return timer_idx;
}

#if (MAX_RECORD_TIMER_NUM > 0)
UINT8 api_epgevnt_match_timers(date_time *start_time,date_time *end_time)
{
	UINT8 i,match_timer_idx;
	INT32 hh,mm,ss;
	TIMER_SET_CONTENT *ptimer;
	date_time sys_starttime,sys_endtime,timer_start,timer_end;
	SYSTEM_DATA *psys_data;

	match_timer_idx = 0xFF;
	psys_data = sys_data_get();
	for(i = 0; i < MAX_RECORD_TIMER_NUM;i++)
	{
		ptimer = &psys_data->timer_set.TimerContent[i + MAX_COMMON_TIMER_NUM];
		if(ptimer->timer_mode != TIMER_MODE_OFF)
		{
			get_STC_offset(&hh,&mm,&ss);
			convert_time_by_offset(&sys_starttime,start_time,hh,mm);
			convert_time_by_offset(&sys_endtime,end_time,hh,mm);//add time offset
			
			timer_start.year = ptimer->wakeup_year;
			timer_start.month = ptimer->wakeup_month;
			timer_start.day = ptimer->wakeup_day;
			timer_start.hour = (ptimer->wakeup_time / 60);
			timer_start.min = (ptimer->wakeup_time % 60);

			if(api_compare_day_time(&sys_starttime,&timer_start) != 0)
			{
				continue;
			}
			else
			{
				//start time match,then end_time
				timer_end.year = ptimer->wakeup_year;
				timer_end.month = ptimer->wakeup_month;
				timer_end.day = ptimer->wakeup_day;
				timer_end.hour = ((ptimer->wakeup_time + ptimer->wakeup_duration_time) / 60);
				timer_end.min = ((ptimer->wakeup_time + ptimer->wakeup_duration_time) % 60);
				if(api_compare_day_time(&sys_endtime,&timer_end) != 0)
				{
					continue;
				}
				else
				{
					match_timer_idx = i;
					break;
				}
			}
		}
	}
	
	return match_timer_idx;
}
#endif

UINT32 api_get_min_inc(UINT8 min, UINT8 prev_min)
{
    UINT8 offset;
    if (min == prev_min)
        return 0;
#if 1
    if (min > prev_min)
    {
        offset = min - prev_min;
    }
    else
    {
        offset = min + 60 - prev_min;
    }
    return offset;
#else
    if (min > prev_min)
    {
        offset = min - prev_min;
        if (offset == 1)
            return 1;
    }
    else
    {
        offset = prev_min - min;
        if (offset == 59)
            return 1;
    }
    return 0;
#endif
}

UINT32 api_dec_min(UINT8 min)
{
    if (min == 0)
        min = 59;
    else
        min--;

    return min;
}

void api_timers_proc(void)
{
	int i;

	SYSTEM_DATA* sys_data;
	TIMER_SET_T* timer_set;
	TIMER_SET_CONTENT* timer;
	date_time	dt,start_dt,end_dt;

	UINT16  next_yy;
	UINT8   next_mm,next_dd;
	P_NODE p_node;
    BOOL timer_changed = FALSE;
    UINT32 min_inc, ticks;

	UINT8 wakeup_idx = 0;
	UINT32 wakeup_array[4];
	UINT8 expire_idx = 0;
	UINT32 expire_array[4];
	
	get_local_time(&dt);
	sys_data = sys_data_get();
	timer_set = &sys_data->timer_set;

	for(i=0;i<MAX_TIMER_NUM;i++)
	{
		timer = &timer_set->TimerContent[i];
		if(timer->timer_mode == TIMER_MODE_OFF )
		{
            if (timer->wakeup_state != TIMER_STATE_READY)
            {
			    timer->wakeup_state  = TIMER_STATE_READY;
                timer_changed = TRUE;
            }
			continue;
		}


		if( !(timer->timer_service <= TIMER_SERVICE_MESSAGE ) )
		{
			timer->timer_mode = TIMER_MODE_OFF;
			timer->wakeup_state  = TIMER_STATE_READY;
            timer_changed = TRUE;
			continue;
		}

		start_dt.year   = timer->wakeup_year;
		start_dt.month  = timer->wakeup_month;
		start_dt.day    = timer->wakeup_day;
		start_dt.hour   = timer->wakeup_time/60;
		start_dt.min    = timer->wakeup_time%60;
		start_dt.sec    = 0;
        //because program loopback,so dt is not correct.
        //pvr monitor will set accurate wakeup_duration_count,so we judge here.
        if(timer->wakeup_duration_count == 0 && timer->wakeup_state == TIMER_STATE_RUNING)
        {
            //libc_printf("wake up \n");
            timer->wakeup_state  = TIMER_STATE_READY;
            set_next_wakeup_datetime(timer);
            /* Stop the timer immediatelly */
            if(system_state != SYS_STATE_POWER_OFF)
            {
                ap_send_msg(CTRL_MSG_SUBTYPE_CMD_TIMER_EXPIRE, i,FALSE);
            }
            timer_changed = TRUE;
        }

		/* Timer reach to wakeup time */
		if(api_compare_day_time(&start_dt,&dt) == 0)
		{
            timer_changed = TRUE;
			if (timer->wakeup_state == TIMER_STATE_RUNING)
			{
				if(system_state == SYS_STATE_POWER_OFF)
				{
					set_next_wakeup_datetime(timer);
					timer->wakeup_state = TIMER_STATE_READY;
				}
				continue;
			}
			else /* Wakeup a timer */
			{
					/*For message or channel of duration is zero,immediatelly update next wakeup date*/            
					if(timer->timer_service == TIMER_SERVICE_MESSAGE
					|| timer->wakeup_duration_time == 0 )
					{
						if(system_state != SYS_STATE_POWER_OFF) /* To avoid not execuate the timer when system wakeup */
						set_next_wakeup_datetime(timer);
					}


				/* If it's channel timer and specified channel not exit, turn off the timer */
				if(( TIMER_SERVICE_CHANNEL == timer->timer_service)
#ifdef DVR_PVR_SUPPORT				
				||(TIMER_SERVICE_DVR_RECORD == timer->timer_service )
#endif 				
				)
				{
					if(get_prog_by_id(timer->wakeup_channel, &p_node) != DB_SUCCES)
					{
					/* The channel not exit, turn of the timer*/
						timer->timer_mode = TIMER_MODE_OFF;
						continue;
					}
				}

				if(system_state == SYS_STATE_POWER_OFF)
				{
					sys_data->wakeup_timer = i+1;
					power_on_process();
				}
				else
				{
#if 0//def DVR_PVR_SUPPORT	
					extern BOOL rec_timer_pending;
					extern UINT32 pvr_timer_index;
                    extern UINT32 pvr_timer_prog_id;
                    extern UINT32 pvr_timer_wait_play;
                    extern UINT8            g_ci_card_insert_flag;
					if(TIMER_SERVICE_DVR_RECORD == timer->timer_service)
					{
						pvr_timer_index = i;
                        pvr_timer_prog_id = timer->wakeup_channel;
                        pvr_timer_wait_play = 0;


                        static UINT8 b_first_time;
                        UINT8 rec_prog_ca_mode, cur_prog_ca_mode;
            			UINT16 chan_idx = sys_data_get_cur_group_cur_mode_channel();
            			get_prog_at(chan_idx, &p_node);
                        cur_prog_ca_mode = p_node.ca_mode;
                        if (g_ci_card_insert_flag && b_first_time == 0)
                        {
                            if (p_node.prog_id == pvr_timer_prog_id)
                            {
                                //libc_printf("START UP timer NOT channel change!!!\n");
                                rec_prog_ca_mode = cur_prog_ca_mode;
                                if (rec_prog_ca_mode == 0)
                                    g_ci_card_insert_flag = 0;
                            }
                            else
                            {
                                //libc_printf("START UP timer need channel change!!!\n");
                			    get_prog_by_id(pvr_timer_prog_id, &p_node);
                                rec_prog_ca_mode = p_node.ca_mode;
                                if (rec_prog_ca_mode)
                                {
                                    //libc_printf("Send START UP timer play channel!!!\n");
                                    ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_SCRIMBLE_SIGN, 4, FALSE);
                                }
                                else
                                    g_ci_card_insert_flag = 0;
                            }
                        }
                        else
                        {
                            if (p_node.prog_id == pvr_timer_prog_id)
                            {
                                ;//libc_printf("Runtime timer NOT channel change!!!\n");
                            }
                            else
                            {
                                //libc_printf("Runtime timer need channel change!!!\n");
                			    get_prog_by_id(pvr_timer_prog_id, &p_node);
                                if (p_node.ca_mode)
                                {
                                    //libc_printf("Send Runtime timer play channel!!!\n");
                                    pvr_timer_wait_play = osal_get_tick() + 5000;
                                    ap_send_msg(CTRL_MSG_SUBTYPE_STATUS_SCRIMBLE_SIGN, 4, FALSE);
                                }
                            }
                        }
                        b_first_time = 1;

						rec_timer_pending = TRUE;
					}
#else
					wakeup_array[wakeup_idx++] = i;
					//ap_send_msg(CTRL_MSG_SUBTYPE_CMD_TIMER_WAKEUP, i,TRUE);
#endif
				}
				
				/* Make the timer a running status. */
				if(timer->timer_mode != TIMER_MODE_OFF)
				{
					timer->wakeup_state  = TIMER_STATE_RUNING;
                    timer->wakeup_duration_count = timer->wakeup_duration_time;
                    timer->wakeup_tick = osal_get_tick();
                    timer->timer_min = api_dec_min(dt.min);
#if 0//def DVR_PVR_SUPPORT
					if (timer->timer_service == TIMER_SERVICE_DVR_RECORD)
					{
                        // Let PVR control the end time at first, then Timer proc
                        timer->wakeup_duration_count++;
					}
#endif
				}
			}
		}
		else    /* Timer not reach to wakeup time */
		{
			/* Message timer or duration==0 timer in running state will not hold other than the wakeup minute */
			if(timer->wakeup_state  == TIMER_STATE_RUNING)
			{
				if(timer->timer_service == TIMER_SERVICE_MESSAGE
					|| timer->wakeup_duration_time == 0)
				{
					timer->wakeup_state = TIMER_STATE_READY;
                    timer_changed = TRUE;
				}
			}
			/* If a timer is running. */
			if(timer->wakeup_state  == TIMER_STATE_RUNING)
			{
#if 1
                ticks = osal_get_tick();
                min_inc = api_get_min_inc(dt.min, timer->timer_min);
                if (min_inc)
                {
                    if ((ticks - timer->wakeup_tick) >= (58500))
                    {
                        //libc_printf("min_inc = %d, ticks = %d, wakeup_tick = %d, interval = %d\n", min_inc, ticks, timer->wakeup_tick, ticks - timer->wakeup_tick);
                        if (timer->wakeup_duration_count)
                            timer->wakeup_duration_count--;
                        if (timer->wakeup_duration_count == 0) /* Reach to end time */
        				{
        					timer->wakeup_state  = TIMER_STATE_READY;
        					set_next_wakeup_datetime(timer);
        					/* Stop the timer immediatelly */
        					if(system_state != SYS_STATE_POWER_OFF)
        					{
        						ap_send_msg(CTRL_MSG_SUBTYPE_CMD_TIMER_EXPIRE, i,FALSE);
        					}
                            timer_changed = TRUE;
        				}
                        timer->wakeup_tick = ticks;
                        timer->timer_min = dt.min;
                    }
                }
#else
				if(api_compare_day_time(&start_dt,&dt)>0)
					timer->wakeup_state=TIMER_STATE_READY;
				/* Get timer expire time.*/
				convert_time_by_offset(&end_dt,&start_dt,
				timer->wakeup_duration_time/60,timer->wakeup_duration_time%60);

				if(api_compare_day_time_ext(&end_dt, &dt) <= 0) /* Reach to end time */
				{					
					timer->wakeup_state  = TIMER_STATE_READY;
					set_next_wakeup_datetime(timer);
					/* Stop the timer immediatelly */
					if(system_state != SYS_STATE_POWER_OFF)
					{
						expire_array[expire_idx++] = i;
						//ap_send_msg(CTRL_MSG_SUBTYPE_CMD_TIMER_EXPIRE, i,FALSE);
					}
				} 
                timer_changed = TRUE;
#endif
			} 
			else    /*The timer is not running*/
			{
				if(api_compare_day_time(&start_dt,&dt)<0)
				{
					/*Check timers date&time setting*/
					/* If date date&time is previous that current date&time, update date&time */
					set_next_wakeup_datetime(timer);
                    timer_changed = TRUE;
				}
			}
		}
	}   

	if(expire_idx)
	{
		for(i=0; i<expire_idx; i++)
		{
			ap_send_msg(CTRL_MSG_SUBTYPE_CMD_TIMER_EXPIRE, expire_array[i], FALSE);
		}
	}
	if(wakeup_idx)
	{
		for(i=0; i<wakeup_idx; i++)
		{
			ap_send_msg(CTRL_MSG_SUBTYPE_CMD_TIMER_WAKEUP, wakeup_array[i], TRUE);
				
			/* Make the timer a running status. */
			if(sys_data->timer_set.TimerContent[wakeup_array[i]].timer_mode != TIMER_MODE_OFF)
				sys_data->timer_set.TimerContent[wakeup_array[i]].wakeup_state  = TIMER_STATE_RUNING;
		}
	}
	
	if (timer_changed)
	{
	    //sys_data_save(1);
	    ap_send_msg(CTRL_MSG_SUBTYPE_CMD_SYSDATA_SAVE, 0,FALSE);
	}
}
// reverse cch characters
void api_str_reverse(UINT16*psz, INT32 cch)
{
	INT32 ich;
	UINT16 chTemp;

	for (ich = 0; ich < --cch; ich++) 
	{
		chTemp = psz[ich];
		psz[ich] = psz[cch];
		psz[cch] = chTemp;
	}
}

 UINT32 api_get_recently_timer()
 {
 	int i;

 	SYSTEM_DATA* sys_data;
 	TIMER_SET_T* timer_set;
 	TIMER_SET_CONTENT* timer;

 	UINT16  yy = 0xFFFF, hm =0xFFFF;
 	UINT8  mm = 0xFF, dd = 0xFF;
 	UINT32	wakeup_time;
 	date_time pmu_timer;

 	sys_data = sys_data_get();
 	timer_set = &sys_data->timer_set;

 	for(i=0;i<MAX_TIMER_NUM;i++)
 	{
 		timer = &timer_set->TimerContent[i];
 		// if(timer->timer_mode == TIMER_MODE_OFF)
 		if(timer->timer_mode == TIMER_MODE_OFF )
 		{
 			timer->wakeup_state = TIMER_STATE_READY;
 			continue;
 		}

 		if(TIMER_STATE_RUNING == timer->wakeup_state)
 		{
 			set_next_wakeup_datetime(timer);
 			timer->wakeup_state = TIMER_STATE_READY;
 		}
 		if( (timer->timer_mode != TIMER_MODE_OFF) && ((timer->wakeup_year < yy) ||
 			((timer->wakeup_year == yy) && (timer->wakeup_month < mm)) ||
 			((timer->wakeup_year == yy) && (timer->wakeup_month == mm) && (timer->wakeup_day < dd)) ||
 			((timer->wakeup_year == yy) && (timer->wakeup_month == mm) && (timer->wakeup_day == dd) && (timer->wakeup_time < hm))))
 		{
 			yy = timer->wakeup_year;
 			mm = timer->wakeup_month;
 			dd = timer->wakeup_day;
 			hm = timer->wakeup_time;
 			sys_data->wakeup_timer = i+1; // base 1

			// find the first timer
			//break;
 		}
 	}
 	if ((hm == 0xFFFF) && (dd == 0xFF) && (mm == 0xFF) && (yy == 0xFFFF))
 	{
 		wakeup_time = 0;
 		sys_data->wakeup_timer = 0x0;
 	}
 	else
 	{
		wakeup_time =0x0| ((hm%60)<<6) | ((hm/60 )<<12) | ((dd & 0x1F)<<17)
 			| ((mm & 0xF) << 22) |  (((yy % 100) & 0x3F)<<26);
  		//set_next_wakeup_datetime(&timer_set->TimerContent[sys_data->wakeup_timer-1]);
          if((ALI_S3811==sys_ic_get_chip_id()) && (sys_ic_get_rev_id() >= IC_REV_1))
        {
            #ifdef PMU_ENABLE

            struct min_alarm alarm={1,1,0,0,0,0,0,0,0,12,16,9,2};
		INT32 o_h=0,o_m=0,o_s=0;
		get_STC_offset(&o_h,&o_m,&o_s);
        pmu_timer.year=yy;
  		pmu_timer.month=mm;
		pmu_timer.day=dd;
		pmu_timer.hour=(UINT8)(hm/60);
		pmu_timer.min=(UINT8)(hm%60);
		convert_time_by_offset(&pmu_timer,&pmu_timer,-o_h,-o_m);
        alarm.en_month=1;
		alarm.en_date=1;
	    alarm.month=pmu_timer.month;
	    alarm.date=pmu_timer.day;
		alarm.hour=pmu_timer.hour;
		alarm.min=pmu_timer.min;
            rtc_s3811_set_min_alarm(&alarm,0,NULL);  //step4,alarm 0 exit standby
	        rtc_s3811_en_alarm(1,0);   //step5,alarm 0 exit standby 
	       
            #endif  
       }
	}
 	
 	return wakeup_time;
 }
 
BOOL api_is_sd_color_mode()
{
	if(OSD_GetCurColorMode() == OSD_256_COLOR)
		return TRUE;

	return FALSE;
}
/*
effect:
    TRUE     vpo dit bob
    FALSE        dit auto
*/
void api_set_vpo_dit(BOOL effect)
{
	struct vpo_device *vpo_new = (struct vpo_device *)dev_get_by_id(HLD_DEV_TYPE_DIS, 0);
#ifdef DUAL_VIDEO_OUTPUT
	struct vpo_device *vpo_old = (struct vpo_device *)dev_get_by_id(HLD_DEV_TYPE_DIS, 1);
#else
    struct vpo_device *vpo_old = NULL;
#endif
    if(effect)
    {
	    vpo_ioctl(vpo_new,VPO_IO_DIT_CHANGE,NORMAL_2_ABNOR);	
	    if(vpo_old != NULL)
	    {
		    vpo_ioctl(vpo_old,VPO_IO_DIT_CHANGE,NORMAL_2_ABNOR);
	    }        
    }
    else
    {
        vpo_ioctl(vpo_new,VPO_IO_DIT_CHANGE,ABNOR_2_NORMAL);	
	    if(vpo_old != NULL)
	    {
		    vpo_ioctl(vpo_old,VPO_IO_DIT_CHANGE,ABNOR_2_NORMAL);	
	    }            
    }
}
#ifdef NEW_DEMO_FRAME
#define MAX_LANG_GROUP_SIZE    6

static char *iso639_lang_multicode[][2] = 
{
    {"fre","fra"},
    {"ger","deu"},
    {"spa","esl"}
};

static UINT8 global_lang_group[MAX_LANG_GROUP_SIZE][4];
static UINT32 global_lang_num;

/*
 * @return: 0 for no need to update @p_node, 1 for need to update @p_node
 */
int get_ch_pids(P_NODE* p_node,UINT16* audioPID,UINT16* ttxPID,UINT16* subtPID,UINT32* audioidx)
{
	UINT32 i,j,k;
	UINT8 lang_in_db[MAX_AUDIO_CNT][4];
    UINT32 audio_cnt;
    UINT32 iso639_cnt = sizeof(iso639_lang_multicode)/sizeof(iso639_lang_multicode[0]);
	int update_database = 1;
    
	MEMSET(lang_in_db,0,sizeof(lang_in_db));

    audio_cnt = p_node->audio_count;
    if(audio_cnt > MAX_AUDIO_CNT)
        audio_cnt = MAX_AUDIO_CNT;

    if(audio_cnt == 0)
    {
        *audioPID = INVALID_PID;
        *audioidx = 0;
    }
    else if(p_node->cur_audio < audio_cnt)
    {
        *audioPID = p_node->audio_pid[p_node->cur_audio];
        *audioidx = p_node->cur_audio;
    }
    else // the case that audio pid number change
    {
        *audioPID = p_node->audio_pid[0];
        *audioidx = 0;
		update_database = 0;
    }

#ifdef AUDIO_DESCRIPTION_SUPPORT
	if (audio_cnt > 0 && AUDIO_TYPE_IS_AUD_DESC(p_node->audio_type[*audioidx]))
	{
		// selected audio is a AD stream, find another one
		for (i = 0; i < audio_cnt; ++i)
		{
			if (!AUDIO_TYPE_IS_AUD_DESC(p_node->audio_type[i]))
			{
				*audioPID = p_node->audio_pid[i];
				*audioidx = i;
				break;
			}
		}
		
		if (i >= audio_cnt)
		{
			*audioPID = INVALID_PID;
			*audioidx = 0;
		}
		if (*audioPID == INVALID_PID) {
			// No main audio,
			// then check is there any broadcast mixed ad
			for (i = 0; i < audio_cnt; ++i)
			{
				if (AUDIO_TYPE_IS_BROADCAST_MIXED_AD(p_node->audio_type[i]))
				{
					*audioPID = p_node->audio_pid[i];
					*audioidx = i;
					break;
				}
			}
		}
	}
#endif

    /* If this channel's audio PID has not been selected by user,then decide
      the audio PID by audio language setting */
    if( !p_node->audio_select)
    {
    	for(i=0;i<audio_cnt;i++)
    		get_audio_lang3b((UINT8 *)&p_node->audio_lang[i],lang_in_db[i]);		
    	
    	for(i=0;i<global_lang_num;i++)
    	{
    		for(j=0;j<audio_cnt;j++)
    		{
    			if ((STRCMP(global_lang_group[i],lang_in_db[j]) == 0)
#ifdef AUDIO_DESCRIPTION_SUPPORT
					&& (!AUDIO_TYPE_IS_AUD_DESC(p_node->audio_type[j]))
#endif
				   )
    			{
    				*audioPID = p_node->audio_pid[j];
                    *audioidx = j;
                    goto GET_AUDIO_PID_DONE;
    			}
                else
                {
                    for(k=0;k<iso639_cnt;k++)
                    {
                        if ((STRCMP(iso639_lang_multicode[k][0],global_lang_group[i]) == 0)
                            && (STRCMP(iso639_lang_multicode[k][1],lang_in_db[j]) == 0)
#ifdef AUDIO_DESCRIPTION_SUPPORT
                            && (!AUDIO_TYPE_IS_AUD_DESC(p_node->audio_type[j]))
#endif
                           )
                        {
                            *audioPID = p_node->audio_pid[j];
                            *audioidx = j;
                            goto GET_AUDIO_PID_DONE;
                        }
                    }
                }
    		}
    	}
    }

GET_AUDIO_PID_DONE:    

    *ttxPID     = p_node->teletext_pid;
    *subtPID    = p_node->subtitle_pid;
	return update_database;
}

UINT32 api_set_audio_language(BYTE* szLangGroup,UINT32 uLangNum)
{
	UINT32 i,j;

	MEMSET(global_lang_group,0,sizeof(global_lang_group));
	if (uLangNum > MAX_LANG_GROUP_SIZE)
		uLangNum = MAX_LANG_GROUP_SIZE;
	for(i=0; i<uLangNum; i++)
	{
		for (j=0;j<3;j++)
		{
			global_lang_group[i][j] = szLangGroup[i*4+j];
		}
	}

	global_lang_num = uLangNum;
	return uLangNum;
}
#endif

#ifdef AV_DELAY_SUPPORT
/*
 *  
 * value: delay value,  0<=value<500 video delay; 500<=value<=1000 audio delay
 * return: NULL
 */
void api_set_avdelay_value(UINT32 value, UINT32 play_mode)
{
	switch(play_mode)
	{
		case AVDELAY_LIVE_PLAY_MODE:
			if(value >= 500 && value <= 1000)
			{
				//libc_printf("%s--- delay audio %dms(500~1000)\n",__FUNCTION__, value-500);
				snd_io_control(g_snd_dev, SND_SET_SYNC_DELAY, value-500);//0-500);
				vdec_io_control(get_selected_decoder(), VDEC_IO_SET_SYNC_DELAY, 0);
			}
			else if(value < 500)
			{
				//libc_printf("%s--- delay audio %dms(0~500)\n",__FUNCTION__, value-500);
				snd_io_control(g_snd_dev, SND_SET_SYNC_DELAY, 0);//0-500);
		   	    vdec_io_control(get_selected_decoder(), VDEC_IO_SET_SYNC_DELAY, 500-value);
			}
			break;
		case AVDELAY_MEDIA_PLAY_MODE:
			if(value >= 500 && value <= 1000)
			{
				//libc_printf("%s---media player delay audio %dms(500~1000)\n",__FUNCTION__, value-500);
				MpgSetAVSyncDelay(1, value-500);
			}
			else if(value < 500)
			{
				//libc_printf("%s---media player delay audio %dms (0~500)\n",__FUNCTION__, value-500);
				MpgSetAVSyncDelay(0, 500-value);
			}
			break;
		default:break;
			
	}
	
}

#endif
#ifdef HDMI_ENABLE
INT32 api_get_HDMI_all_video_resolution(UINT32 *native_res_index, enum HDMI_API_RES *support_res)
{
	UINT32 i, j, tmp;
	UINT32 count;
	
	MEMSET(support_res,0,sizeof(enum HDMI_API_RES)*8);
	if (api_get_edid_all_video_resolution(native_res_index, support_res) == SUCCESS)
	{
		for (count=0; count<8 && support_res[count]!=HDMI_RES_INVALID; count++)
		{
		}

		if (count == 0)
			return !SUCCESS;

		// Bubble sort for HDMI resolution
		for (i = 0; i<count-1; i++)
		{
			for(j=0;j<count-1-i; j++)
			{
				if((UINT32)support_res[j] > (UINT32)support_res[j+1])
					{
						tmp = support_res[j];
						support_res[j] = support_res[j+1];
						support_res[j+1] = tmp;
					}
			}
		}
		// ignore the miss of native_res_index
		return SUCCESS;	
	}
	return !SUCCESS;
}
#endif

#ifdef _INVW_JUICE //v0.1.4
UINT8 api_get_chuck_addlen(UINT32 id,UINT32* addr,UINT32* len)
{
	INT32 ret;
	CHUNK_HEADER chuck_hdr;

	ret = sto_get_chunk_header(id,&chuck_hdr);
	if(ret==0)
		return 0;

	*addr = (UINT32)sto_chunk_goto(&id,0xFFFFFFFF,1) + CHUNK_HEADER_SIZE;
	*len = chuck_hdr.len - CHUNK_HEADER_SIZE + CHUNK_NAME;

	return 1;
}
#endif
#define INVALID_SAT_ID  0xFFFF

UINT16 get_frontend_satid(UINT8 frontend_type, UINT8 is_isdbt)
{
    if(frontend_type == dev_get_device_sub_type(dev_get_by_id(HLD_DEV_TYPE_NIM, 0), HLD_DEV_TYPE_NIM) &&
        is_isdbt == board_frontend_is_isdbt(0))
        return board_get_frontend_satid(0);
    else if(frontend_type == dev_get_device_sub_type(dev_get_by_id(HLD_DEV_TYPE_NIM, 1), HLD_DEV_TYPE_NIM) &&
        is_isdbt == board_frontend_is_isdbt(1))
        return board_get_frontend_satid(1);
    else
        return INVALID_SAT_ID;
}


#if 0
#define VHF_LOW_BAND	140000//Band thresheld of VHF low band and VHF high band
void get_default_bandparam(UINT8 index, Band_param *buf)
{
	Band_param tempbuf[MAX_BAND_COUNT], tempbuf2[MAX_BAND_COUNT], tempbuf_sub;
	UINT32 offset_addr = 0;
	UINT32 addr = 0;
	
	BYTE	i , k = 0;
	Band_param *tempptr= &tempbuf[0];
	UINT32 COUNTRYBAND_ID = 0x06F90100;
	
	//addr = DEFAULT_VALUE_BASE_ADDR;
	addr = SYS_FLASH_BASE_ADDR + (UINT32)sto_chunk_goto(&COUNTRYBAND_ID,0xFFFFFFFF,1) + 128;
	offset_addr = index * sizeof(tempbuf);
	addr = addr + offset_addr;
#if 0//all band
	MEMCPY(buf, (void*)addr, sizeof(tempbuf));
#else//depend on Tuner spec
	MEMCPY(&tempbuf, (void*)addr, sizeof(tempbuf));
	MEMSET(&tempbuf2, 0, sizeof(tempbuf2));
	for (i = 0; i < MAX_BAND_COUNT ; i++)//0~9
	{
		tempptr = &tempbuf[i];
		if (  VHF_LOW_BAND  >= tempptr->start_freq )
		{
		}
		else 
		{
			MEMCPY(&tempbuf2[k], tempptr, sizeof(tempbuf_sub));
			k++;
		}
	}

	MEMCPY(buf, &tempbuf2, sizeof(tempbuf2));
#endif
}
#endif

//add on 2011-11-02 for combo ui
UINT8 get_combo_config_frontend(void)
{
    INT32 i;
    UINT8 count=0;
    UINT8 s_front = 0,t_front = 0,isdbt_front = 0,c_front = 0;
    
    for(i = 0; i < 2; i++)
    {
        switch(board_get_frontend_type(i))
        {
            case FRONTEND_TYPE_S:
                s_front++;
                break;
            case FRONTEND_TYPE_T:
                if(board_frontend_is_isdbt(i))
                    isdbt_front++;
                else
                    t_front++;
                break;
            case FRONTEND_TYPE_C:
                c_front++;
                break;                
            default:
                break;
        }  
    }

    if(s_front == 2 || t_front == 2|| isdbt_front == 2|| c_front == 2 || (s_front + t_front + isdbt_front + c_front == 1))
        count = 1;
    else
    {
        if(s_front + t_front + isdbt_front + c_front == 2)
        {
            count = 2;
        }
    }
    
    return count;
}

UINT8 get_combo_tuner_num(void)
{
    INT32 i;
    UINT8 count=0;
    UINT8 s_front = 0,t_front = 0,isdbt_front = 0,c_front = 0;
    
    for(i = 0; i < 2; i++)
    {
        switch(board_get_frontend_type(i))
        {
            case FRONTEND_TYPE_S:
                s_front++;
                break;
            case FRONTEND_TYPE_T:
                if(board_frontend_is_isdbt(i))
                    isdbt_front++;
                else
                    t_front++;
                break;
            case FRONTEND_TYPE_C:
                c_front++;
                break;                
            default:
                break;
        }  
    }

    if(s_front == 2 || t_front == 2|| isdbt_front == 2|| c_front == 2)
        count = 2;
    else
    {
        if(s_front + t_front + isdbt_front + c_front == 2)
        {
            count = 2;
        }
        else if(s_front + t_front + isdbt_front + c_front == 1)
        {
            count = 1;
        }
    }
    
    return count;
}


//add on 2011-11-02 for combo ui
BOOL check_frontend_type(UINT8 frontend_type, UINT8 is_isdbt)
{
 
    if(frontend_type == board_get_frontend_type(0) && is_isdbt == board_frontend_is_isdbt(0))
        return TRUE;
    else if(frontend_type == board_get_frontend_type(1) && is_isdbt == board_frontend_is_isdbt(1))
        return TRUE;
    else
        return FALSE;
}

//add on 2011-11-02 for combo ui
void set_combo_chan_idx(UINT8 frontend_kind,  T_NODE t_node, P_NODE p_node, UINT16 chan_idx, char *str)
{
#ifdef _LCN_ENABLE_
	UINT8 dvb_combo=0;
	db_get_dvb_combo(&dvb_combo); // 0:dvbc, dvbs  1:dvbt  2:isdbt  3:dvbt+dvbs 4:isdbt+dvbs

	if((dvb_combo == 2 || dvb_combo == 4) && sys_data_get_LCN())
	{
		if(t_node.remote_control_key_id !=100)
			sprintf(str,"%02d-%01d%1d    ", t_node.remote_control_key_id, (p_node.prog_number & 0x1f)>>3, (p_node.prog_number & 0x07)+1);
		else
			sprintf(str,"%02d-%04d", 0x00, p_node.LCN);
	}
	else if((dvb_combo == 1 || dvb_combo==3) && sys_data_get_LCN())
	{
		 sprintf(str,"%04d",p_node.LCN);
	}
	else
#endif
		sprintf(str,"%04d",chan_idx + 1);
    
}


//for combo test 
#include <api/libosd/osd_lib.h>
#if 0
void init_default_value(void)
{
    S_NODE node;
#if _ISDBT_ENABLE_   
    char* s_name = "ISDBT";
    UINT8 max_cnt = 5;
#endif
#if _DVBT_ENABLE_
    char* s_name = "DVBT";
    UINT8 max_cnt = 4;
#endif

    if(SUCCESS != clear_db())
        return;

    update_data();

    recreate_sat_view(VIEW_ALL,0);
    
    MEMSET(&node, 0, sizeof(S_NODE));    
    ComStr2UniStrExt((UINT16*)node.sat_name, s_name, max_cnt);

    if(FRONTEND_TYPE_T == dev_get_device_sub_type(g_nim_dev, HLD_DEV_TYPE_NIM))
        node.tuner1_valid = 1;
    else if(FRONTEND_TYPE_T == dev_get_device_sub_type(g_nim_dev2, HLD_DEV_TYPE_NIM))
        node.tuner2_valid = 1;
        
    INT32 iret = add_node(TYPE_SAT_NODE,0,&node);
    libc_printf("add sat node id: %d\n", node.sat_id);
    
    MEMSET(&node, 0, sizeof(S_NODE));
    node.sat_orbit = 260;
    node.lnb_type = 0;
    node.lnb_low = 5150;
    node.lnb_high = 5750;
    ComStr2UniStrExt((UINT16*)node.sat_name, "DVBS2", 5);
    iret = add_node(TYPE_SAT_NODE,0,&node);
    if((iret == DBERR_MAX_LIMIT) || (iret == DBERR_FLASH_FULL))
    {
        return;
    }    
    libc_printf("add sat node id: %d\n", node.sat_id);
    update_data();           
}
#endif
#ifdef AUTO_OTA
#if(defined(DVBT_SUPPORT)||defined(ISDBT_SUPPORT)||defined(DVBC_SUPPORT))
BOOL api_ota_get_recently_timer(date_time*  wakeup_time)
{
	BOOL ret = FALSE;

 	UINT16  yy = 0xFFFF, hm =0xFFFF;
 	UINT8  mm = 0xFF, dd = 0xFF, ss = 0xFF, i;
	SYSTEM_DATA* sys_data;
	TIMER_SET_T* timer_set;
	TIMER_SET_CONTENT* timer;

	MEMSET(wakeup_time, 0, sizeof(date_time));
	sys_data = sys_data_get();
	timer_set = &sys_data->timer_set;

	for(i=0;i<MAX_TIMER_NUM;i++)
 	{
 		timer = &timer_set->TimerContent[i];
 		if( (timer->timer_mode != TIMER_MODE_OFF) && ((timer->wakeup_year < yy) ||
 			((timer->wakeup_year == yy) && (timer->wakeup_month < mm)) ||
 			((timer->wakeup_year == yy) && (timer->wakeup_month == mm) && (timer->wakeup_day < dd)) ||
 			((timer->wakeup_year == yy) && (timer->wakeup_month == mm) && (timer->wakeup_day == dd) && (timer->wakeup_time < hm))))
 		{
 			yy = timer->wakeup_year;
 			mm = timer->wakeup_month;
 			dd = timer->wakeup_day;
 			hm = timer->wakeup_time;
 		}
 	}
 	if ((hm == 0xFFFF) && (dd == 0xFF) && (mm == 0xFF) && (yy == 0xFFFF))
 	{
 		ret = FALSE;
 	}
 	else
 	{
		if(hm == 0)
		{
			hm = 1439;
			dd -= 1;
			api_correct_yy_mm_dd(&yy,&mm,&dd,0);
		}
		else
			hm-=1;    

		wakeup_time->year = yy;
		wakeup_time->month = mm;
		wakeup_time->day = dd;
		wakeup_time->hour = hm/60;
		wakeup_time->min = hm%60;
		wakeup_time->sec = 0;

		ret = TRUE;

}
		
 	return ret;
}
#endif
#endif
//add by bill 2012.02.24
void api_uart_enable(BOOL mode)
{
	if( mode != FALSE )
	{
		*(volatile UINT32*)(0xb8000430) &=~(3<<15);
		*(volatile UINT32*)(0xb8000088) |= 1<<8;
	}
	else
	{
		*(volatile UINT32*)(0xb8000088) &= ~(1<<8); 
		*(volatile UINT32*)(0xb8000430) |=(1<<16);
		HAL_GPIO_BIT_DIR_SET( 16, 1);	
		*(volatile UINT32*)(0xb8000054)&=~(1<<16);
		*(volatile UINT32*)(0xb8000430) |=(1<<15);
		HAL_GPIO_BIT_DIR_SET( 15, 1);	
		*(volatile UINT32*)(0xb8000054)|=(1<<15);
	}
	return;
}
